Revision 57596
Added by Michele Artini over 4 years ago
modules/dnet-orgs-database-application/trunk/src/main/java/eu/dnetlib/organizations/repository/UserCountryRepository.java | ||
---|---|---|
1 |
package eu.dnetlib.organizations.repository; |
|
2 |
|
|
3 |
import org.springframework.data.jpa.repository.JpaRepository; |
|
4 |
|
|
5 |
import eu.dnetlib.organizations.model.UserCountry; |
|
6 |
import eu.dnetlib.organizations.model.UserCountryPK; |
|
7 |
|
|
8 |
public interface UserCountryRepository extends JpaRepository<UserCountry, UserCountryPK> { |
|
9 |
|
|
10 |
void deleteByEmail(String email); |
|
11 |
} |
modules/dnet-orgs-database-application/trunk/src/main/java/eu/dnetlib/organizations/model/UserCountry.java | ||
---|---|---|
1 |
package eu.dnetlib.organizations.model; |
|
2 |
|
|
3 |
import java.io.Serializable; |
|
4 |
|
|
5 |
import javax.persistence.Column; |
|
6 |
import javax.persistence.Entity; |
|
7 |
import javax.persistence.Id; |
|
8 |
import javax.persistence.IdClass; |
|
9 |
import javax.persistence.Table; |
|
10 |
|
|
11 |
@Entity |
|
12 |
@Table(name = "user_countries") |
|
13 |
@IdClass(UserCountryPK.class) |
|
14 |
public class UserCountry implements Serializable { |
|
15 |
|
|
16 |
/** |
|
17 |
* |
|
18 |
*/ |
|
19 |
private static final long serialVersionUID = 3493897777214583701L; |
|
20 |
|
|
21 |
@Id |
|
22 |
@Column(name = "email") |
|
23 |
private String email; |
|
24 |
|
|
25 |
@Id |
|
26 |
@Column(name = "country") |
|
27 |
private String country; |
|
28 |
|
|
29 |
public UserCountry() {} |
|
30 |
|
|
31 |
public UserCountry(final String email, final String country) { |
|
32 |
this.email = email; |
|
33 |
this.country = country; |
|
34 |
} |
|
35 |
|
|
36 |
public String getEmail() { |
|
37 |
return email; |
|
38 |
} |
|
39 |
|
|
40 |
public void setEmail(final String email) { |
|
41 |
this.email = email; |
|
42 |
} |
|
43 |
|
|
44 |
public String getCountry() { |
|
45 |
return country; |
|
46 |
} |
|
47 |
|
|
48 |
public void setCountry(final String country) { |
|
49 |
this.country = country; |
|
50 |
} |
|
51 |
|
|
52 |
} |
modules/dnet-orgs-database-application/trunk/src/main/java/eu/dnetlib/organizations/model/UserCountryPK.java | ||
---|---|---|
1 |
package eu.dnetlib.organizations.model; |
|
2 |
|
|
3 |
import java.io.Serializable; |
|
4 |
import java.util.Objects; |
|
5 |
|
|
6 |
public class UserCountryPK implements Serializable { |
|
7 |
|
|
8 |
/** |
|
9 |
* |
|
10 |
*/ |
|
11 |
private static final long serialVersionUID = 2003686130380208901L; |
|
12 |
|
|
13 |
private String email; |
|
14 |
|
|
15 |
private String country; |
|
16 |
|
|
17 |
public String getEmail() { |
|
18 |
return email; |
|
19 |
} |
|
20 |
|
|
21 |
public void setEmail(final String email) { |
|
22 |
this.email = email; |
|
23 |
} |
|
24 |
|
|
25 |
public String getCountry() { |
|
26 |
return country; |
|
27 |
} |
|
28 |
|
|
29 |
public void setCountry(final String country) { |
|
30 |
this.country = country; |
|
31 |
} |
|
32 |
|
|
33 |
@Override |
|
34 |
public int hashCode() { |
|
35 |
return Objects.hash(country, email); |
|
36 |
} |
|
37 |
|
|
38 |
@Override |
|
39 |
public boolean equals(final Object obj) { |
|
40 |
if (this == obj) { return true; } |
|
41 |
if (obj == null) { return false; } |
|
42 |
if (!(obj instanceof UserCountryPK)) { return false; } |
|
43 |
final UserCountryPK other = (UserCountryPK) obj; |
|
44 |
return Objects.equals(country, other.country) && Objects.equals(email, other.email); |
|
45 |
} |
|
46 |
|
|
47 |
@Override |
|
48 |
public String toString() { |
|
49 |
return String.format("UserCountryPK [email=%s, country=%s]", email, country); |
|
50 |
} |
|
51 |
|
|
52 |
} |
modules/dnet-orgs-database-application/trunk/src/main/java/eu/dnetlib/organizations/utils/DatabaseUtils.java | ||
---|---|---|
9 | 9 |
import org.springframework.cache.annotation.Cacheable; |
10 | 10 |
import org.springframework.jdbc.core.JdbcTemplate; |
11 | 11 |
import org.springframework.stereotype.Component; |
12 |
import org.springframework.web.bind.annotation.RequestBody; |
|
12 | 13 |
|
13 | 14 |
import eu.dnetlib.organizations.model.Acronym; |
14 | 15 |
import eu.dnetlib.organizations.model.Organization; |
... | ... | |
16 | 17 |
import eu.dnetlib.organizations.model.OtherName; |
17 | 18 |
import eu.dnetlib.organizations.model.Relationship; |
18 | 19 |
import eu.dnetlib.organizations.model.Url; |
20 |
import eu.dnetlib.organizations.model.User; |
|
21 |
import eu.dnetlib.organizations.model.UserCountry; |
|
19 | 22 |
import eu.dnetlib.organizations.model.view.OrganizationView; |
23 |
import eu.dnetlib.organizations.model.view.UserView; |
|
20 | 24 |
import eu.dnetlib.organizations.repository.AcronymRepository; |
21 | 25 |
import eu.dnetlib.organizations.repository.OrganizationRepository; |
22 | 26 |
import eu.dnetlib.organizations.repository.OtherIdentifierRepository; |
23 | 27 |
import eu.dnetlib.organizations.repository.OtherNameRepository; |
24 | 28 |
import eu.dnetlib.organizations.repository.RelationshipRepository; |
25 | 29 |
import eu.dnetlib.organizations.repository.UrlRepository; |
30 |
import eu.dnetlib.organizations.repository.UserCountryRepository; |
|
31 |
import eu.dnetlib.organizations.repository.UserRepository; |
|
26 | 32 |
|
27 | 33 |
@Component |
28 | 34 |
public class DatabaseUtils { |
... | ... | |
39 | 45 |
private UrlRepository urlRepository; |
40 | 46 |
@Autowired |
41 | 47 |
private RelationshipRepository relationshipRepository; |
48 |
@Autowired |
|
49 |
private UserRepository userRepository; |
|
50 |
@Autowired |
|
51 |
private UserCountryRepository userCountryRepository; |
|
42 | 52 |
|
43 | 53 |
@Autowired |
44 | 54 |
private JdbcTemplate jdbcTemplate; |
... | ... | |
119 | 129 |
return jdbcTemplate.queryForList("select country from user_countries where email = ?", String.class, name); |
120 | 130 |
} |
121 | 131 |
|
132 |
@Transactional |
|
133 |
public void saveUser(@RequestBody final UserView userView) { |
|
134 |
|
|
135 |
final User user = userRepository.findById(userView.getEmail()).orElseThrow(() -> new RuntimeException("User not found")); |
|
136 |
user.setRole(userView.getRole()); |
|
137 |
user.setValid(userView.isValid()); |
|
138 |
userRepository.save(user); |
|
139 |
|
|
140 |
userCountryRepository.deleteByEmail(userView.getEmail()); |
|
141 |
for (final String country : userView.getCountries()) { |
|
142 |
userCountryRepository.save(new UserCountry(userView.getEmail(), country)); |
|
143 |
} |
|
144 |
} |
|
145 |
|
|
146 |
@Transactional |
|
147 |
public void deleteUser(final String email) { |
|
148 |
userCountryRepository.deleteByEmail(email); |
|
149 |
userRepository.deleteById(email); |
|
150 |
} |
|
151 |
|
|
122 | 152 |
} |
modules/dnet-orgs-database-application/trunk/src/main/java/eu/dnetlib/organizations/controller/UserController.java | ||
---|---|---|
5 | 5 |
|
6 | 6 |
import org.apache.commons.codec.digest.DigestUtils; |
7 | 7 |
import org.springframework.beans.factory.annotation.Autowired; |
8 |
import org.springframework.security.core.Authentication; |
|
9 |
import org.springframework.web.bind.annotation.DeleteMapping; |
|
8 | 10 |
import org.springframework.web.bind.annotation.GetMapping; |
9 | 11 |
import org.springframework.web.bind.annotation.PostMapping; |
12 |
import org.springframework.web.bind.annotation.RequestBody; |
|
10 | 13 |
import org.springframework.web.bind.annotation.RequestParam; |
11 | 14 |
import org.springframework.web.bind.annotation.RestController; |
12 | 15 |
|
... | ... | |
14 | 17 |
import eu.dnetlib.organizations.model.view.UserView; |
15 | 18 |
import eu.dnetlib.organizations.repository.UserRepository; |
16 | 19 |
import eu.dnetlib.organizations.repository.readonly.UserViewRepository; |
20 |
import eu.dnetlib.organizations.utils.DatabaseUtils; |
|
17 | 21 |
import eu.dnetlib.organizations.utils.OpenOrgsConstants; |
18 | 22 |
|
19 | 23 |
@RestController |
... | ... | |
25 | 29 |
private UserRepository userRepository; |
26 | 30 |
@Autowired |
27 | 31 |
private UserViewRepository userViewRepository; |
32 |
@Autowired |
|
33 |
private DatabaseUtils dbUtils; |
|
28 | 34 |
|
29 | 35 |
@PostMapping(value = "/public_api/newUser") |
30 | 36 |
public Map<String, Integer> newUser(final @RequestParam String email) { |
... | ... | |
48 | 54 |
return userViewRepository.findAll(); |
49 | 55 |
} |
50 | 56 |
|
57 |
@PostMapping("/api/users") |
|
58 |
public Iterable<UserView> save(@RequestBody final UserView userView, final Authentication authentication) { |
|
59 |
if (authentication.getName().equals(userView.getEmail())) { throw new RuntimeException("You can't edit your own user"); } |
|
60 |
dbUtils.saveUser(userView); |
|
61 |
return users(); |
|
62 |
} |
|
63 |
|
|
64 |
@DeleteMapping("/api/users") |
|
65 |
public Iterable<UserView> delete(final @RequestParam String email, final Authentication authentication) { |
|
66 |
if (authentication.getName().equals(email)) { throw new RuntimeException("You can't delete your own user"); } |
|
67 |
dbUtils.deleteUser(email); |
|
68 |
return users(); |
|
69 |
} |
|
70 |
|
|
51 | 71 |
} |
modules/dnet-orgs-database-application/trunk/src/main/resources/sql/schema.sql | ||
---|---|---|
188 | 188 |
u.email, |
189 | 189 |
u.valid, |
190 | 190 |
u.role, |
191 |
array_agg(uc.country) AS countries |
|
191 |
array_agg(uc.country) FILTER (WHERE uc.country IS NOT NULL) AS countries
|
|
192 | 192 |
FROM |
193 | 193 |
users u |
194 | 194 |
LEFT OUTER JOIN user_countries uc ON (u.email = uc.email) |
modules/dnet-orgs-database-application/trunk/src/main/resources/static/resources/html/users.html | ||
---|---|---|
1 | 1 |
<table class="table table-sm table-hover col-sm-12 col-md-10 col-lg-8"> |
2 | 2 |
<thead class="thead-light"> |
3 | 3 |
<tr class="d-flex"> |
4 |
<th class="col-4">User</th>
|
|
5 |
<th class="col-2 text-center">Valid</th>
|
|
6 |
<th class="col-2 text-center">Role</th>
|
|
4 |
<th class="col-5">User</th>
|
|
5 |
<th class="col-1 text-center">Enabled</th>
|
|
6 |
<th class="col-1 text-center">Is admin</th>
|
|
7 | 7 |
<th class="col-3">Countries</th> |
8 |
<th class="col-1"></th>
|
|
8 |
<th class="col-2"></th>
|
|
9 | 9 |
</tr> |
10 | 10 |
</thead> |
11 | 11 |
<tbody> |
12 |
<tr ng-repeat="u in users" class="d-flex"> |
|
13 |
<td class="col-4">{{u.email}}</td> |
|
14 |
<td class="col-2 text-center">{{u.valid}}</td> |
|
15 |
<td class="col-2 text-center">{{u.role}}</td> |
|
16 |
<td class="col-3">{{u.countries}}</td> |
|
17 |
<td class="col-1 text-right"><button type="button" class="btn btn-sm btn-outline-danger"><i class="fa fa-trash"></i></button></td> |
|
12 |
<tr ng-repeat="u in users" class="d-flex" ng-class="{'table-danger' : u.role == 'PENDING'}"> |
|
13 |
<th class="col-5" ng-class="{'text-secondary': !u.valid}">{{u.email}}</th> |
|
14 |
<td class="col-1 text-center text-success"> |
|
15 |
<i class="fa fa-check-circle" ng-if="u.valid"></i> |
|
16 |
</td> |
|
17 |
<td class="col-1 text-center"> |
|
18 |
<i class="fa fa-check-circle" ng-if="u.role == 'SUPERUSER'"></i> |
|
19 |
<span class="text-warning" ng-if="u.role == 'PENDING'">not configured</span> |
|
20 |
</td> |
|
21 |
<td class="col-3"> |
|
22 |
<span ng-if="u.role == 'USER'"> |
|
23 |
<img ng-src="resources/images/flags/{{c}}.gif" title="{{c}}" class="mr-1" ng-repeat="c in u.countries" /> |
|
24 |
<span class="text-warning" ng-if="u.countries.length == 0"><i class="fa fa-exclamation-triangle"></i> no countries</span> |
|
25 |
</span> |
|
26 |
<span class="text-muted" ng-if="u.role == 'SUPERUSER'">All countries</span> |
|
27 |
<span class="text-warning" ng-if="u.role == 'PENDING'">not configured</span> |
|
28 |
|
|
29 |
</td> |
|
30 |
<td class="col-2 text-right"> |
|
31 |
<a href="mailto:{{u.email}}" class="btn btn-sm btn-outline-info"><i class="fa fa-at"></i></a> |
|
32 |
<button type="button" class="btn btn-sm btn-outline-info" data-toggle="modal" data-target="#editUserModal" ng-click="setCurrentUser(u)"><i class="fa fa-edit"></i></button> |
|
33 |
<button type="button" class="btn btn-sm btn-outline-danger" ng-click="deleteUser(u.email)"><i class="fa fa-trash"></i></button> |
|
34 |
</td> |
|
18 | 35 |
</tr> |
19 | 36 |
</tbody> |
20 | 37 |
</table> |
21 | 38 |
|
22 | 39 |
|
40 |
<div class="modal fade" id="editUserModal" tabindex="-1" role="dialog"> |
|
41 |
<div class="modal-dialog modal-xl" role="document"> |
|
42 |
<div class="modal-content"> |
|
43 |
<div class="modal-header"> |
|
44 |
<h5 class="modal-title">Edit user</h5> |
|
45 |
<button type="button" class="close" data-dismiss="modal">×</button> |
|
46 |
</div> |
|
47 |
<div class="modal-body" style="min-height: 300px; max-height: 500px; overflow-y: auto;"> |
|
48 |
<form> |
|
49 |
<div class="form-group row"> |
|
50 |
<label class="col-sm-2 col-form-label">Email</label> |
|
51 |
<div class="col-sm-10"><a href="mailto:{{currentUser.email}}">{{currentUser.email}}</a></div> |
|
52 |
</div> |
|
53 |
<div class="form-group row"> |
|
54 |
<label class="col-sm-2 col-form-label">Enabled</label> |
|
55 |
<div class="col-sm-10"> |
|
56 |
<div class="form-check"> |
|
57 |
<input class="form-check-input" type="checkbox" ng-model="currentUser.valid" /> |
|
58 |
</div> |
|
59 |
</div> |
|
60 |
</div> |
|
61 |
<div class="form-group row" ng-if="currentUser.valid"> |
|
62 |
<label class="col-sm-2 col-form-label">Role</label> |
|
63 |
<div class="col-sm-10"> |
|
64 |
<div class="form-check form-check-inline"> |
|
65 |
<input class="form-check-input" type="radio" value="USER" ng-model="currentUser.role"> |
|
66 |
<label class="form-check-label">USER</label> |
|
67 |
</div> |
|
68 |
<div class="form-check form-check-inline"> |
|
69 |
<input class="form-check-input" type="radio" value="SUPERUSER" ng-model="currentUser.role"> |
|
70 |
<label class="form-check-label">SUPERUSER</label> |
|
71 |
</div> |
|
72 |
</div> |
|
73 |
</div> |
|
74 |
|
|
75 |
<div class="card mb-3" ng-if="currentUser.valid && currentUser.role == 'USER'"> |
|
76 |
<div class="card-header bg-primary text-white py-1">Countries</div> |
|
77 |
<div class="card-body"> |
|
78 |
<div class="form-group row"> |
|
79 |
<div class="col-sm-2" ng-repeat="c in vocs.countries"> |
|
80 |
<div class="form-check form-check-inline"> |
|
81 |
<input class="form-check-input" type="checkbox" checklist-model="currentUser.countries" checklist-value="c"/> |
|
82 |
<label class="form-check-label">{{c}}</label> |
|
83 |
</div> |
|
84 |
</div> |
|
85 |
</div> |
|
86 |
</div> |
|
87 |
</div> |
|
88 |
|
|
89 |
</form> |
|
90 |
</div> |
|
91 |
<div class="modal-footer"> |
|
92 |
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> |
|
93 |
<button type="button" class="btn btn-primary" data-dismiss="modal" ng-click="saveUser(currentUser)">Save changes</button> |
|
94 |
</div> |
|
95 |
</div> |
|
96 |
</div> |
|
97 |
</div> |
|
23 | 98 |
|
99 |
|
|
100 |
|
|
101 |
|
modules/dnet-orgs-database-application/trunk/src/main/resources/static/resources/js/organizations.js | ||
---|---|---|
1 |
var orgsModule = angular.module('orgs', ['ngRoute']); |
|
1 |
var orgsModule = angular.module('orgs', ['ngRoute', 'checklist-model']);
|
|
2 | 2 |
|
3 | 3 |
orgsModule.config(function($routeProvider) { |
4 | 4 |
$routeProvider |
... | ... | |
268 | 268 |
|
269 | 269 |
|
270 | 270 |
|
271 |
orgsModule.controller('usersCtrl', function ($scope, $http) { |
|
271 |
orgsModule.controller('usersCtrl', function ($scope, $http, $timeout, $route) {
|
|
272 | 272 |
$scope.users = []; |
273 |
$scope.vocabularies = {}; |
|
273 |
$scope.vocs = {}; |
|
274 |
$scope.currentUser = {}; |
|
274 | 275 |
|
275 | 276 |
$http.get('api/vocabularies').then(function successCallback(res) { |
276 |
$scope.vocabularies = res.data;
|
|
277 |
$scope.vocs = res.data; |
|
277 | 278 |
|
278 | 279 |
$http.get('api/users').then(function successCallback(res) { |
279 | 280 |
$scope.users = res.data; |
... | ... | |
284 | 285 |
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')'); |
285 | 286 |
}); |
286 | 287 |
|
288 |
$scope.setCurrentUser = function(user) { |
|
289 |
angular.copy(user, $scope.currentUser); |
|
290 |
} |
|
291 |
|
|
292 |
$scope.saveUser = function(user) { |
|
293 |
$http.defaults.headers.post["Content-Type"] = "application/json;charset=UTF-8"; |
|
294 |
$http.post('api/users', user).then(function successCallback(res) { |
|
295 |
$scope.users = res.data; |
|
296 |
}, function errorCallback(res) { |
|
297 |
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')'); |
|
298 |
}); |
|
299 |
} |
|
300 |
|
|
301 |
$scope.deleteUser = function(email) { |
|
302 |
if (confirm("Are you sure ?")) { |
|
303 |
$http.delete('api/users?email=' + email).then(function successCallback(res) { |
|
304 |
$scope.users = res.data; |
|
305 |
}, function errorCallback(res) { |
|
306 |
alert('ERROR: ' + res.data.error + ' (' + res.data.message + ')'); |
|
307 |
}); |
|
308 |
} |
|
309 |
} |
|
287 | 310 |
}); |
modules/dnet-orgs-database-application/trunk/src/main/resources/static/resources/js/checklist-model.js | ||
---|---|---|
1 |
/** |
|
2 |
* Checklist-model |
|
3 |
* AngularJS directive for list of checkboxes |
|
4 |
* https://github.com/vitalets/checklist-model |
|
5 |
* License: MIT http://opensource.org/licenses/MIT |
|
6 |
*/ |
|
7 |
|
|
8 |
/* commonjs package manager support (eg componentjs) */ |
|
9 |
if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){ |
|
10 |
module.exports = 'checklist-model'; |
|
11 |
} |
|
12 |
|
|
13 |
angular.module('checklist-model', []) |
|
14 |
.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) { |
|
15 |
// contains |
|
16 |
function contains(arr, item, comparator) { |
|
17 |
if (angular.isArray(arr)) { |
|
18 |
for (var i = arr.length; i--;) { |
|
19 |
if (comparator(arr[i], item)) { |
|
20 |
return true; |
|
21 |
} |
|
22 |
} |
|
23 |
} |
|
24 |
return false; |
|
25 |
} |
|
26 |
|
|
27 |
// add |
|
28 |
function add(arr, item, comparator) { |
|
29 |
arr = angular.isArray(arr) ? arr : []; |
|
30 |
if(!contains(arr, item, comparator)) { |
|
31 |
arr.push(item); |
|
32 |
} |
|
33 |
return arr; |
|
34 |
} |
|
35 |
|
|
36 |
// remove |
|
37 |
function remove(arr, item, comparator) { |
|
38 |
if (angular.isArray(arr)) { |
|
39 |
for (var i = arr.length; i--;) { |
|
40 |
if (comparator(arr[i], item)) { |
|
41 |
arr.splice(i, 1); |
|
42 |
break; |
|
43 |
} |
|
44 |
} |
|
45 |
} |
|
46 |
return arr; |
|
47 |
} |
|
48 |
|
|
49 |
// http://stackoverflow.com/a/19228302/1458162 |
|
50 |
function postLinkFn(scope, elem, attrs) { |
|
51 |
// exclude recursion, but still keep the model |
|
52 |
var checklistModel = attrs.checklistModel; |
|
53 |
attrs.$set("checklistModel", null); |
|
54 |
// compile with `ng-model` pointing to `checked` |
|
55 |
$compile(elem)(scope); |
|
56 |
attrs.$set("checklistModel", checklistModel); |
|
57 |
|
|
58 |
// getter for original model |
|
59 |
var checklistModelGetter = $parse(checklistModel); |
|
60 |
var checklistChange = $parse(attrs.checklistChange); |
|
61 |
var checklistBeforeChange = $parse(attrs.checklistBeforeChange); |
|
62 |
var ngModelGetter = $parse(attrs.ngModel); |
|
63 |
|
|
64 |
|
|
65 |
|
|
66 |
var comparator = function (a, b) { |
|
67 |
if(!isNaN(a) && !isNaN(b)) { |
|
68 |
return String(a) === String(b); |
|
69 |
} else { |
|
70 |
return angular.equals(a,b); |
|
71 |
} |
|
72 |
}; |
|
73 |
|
|
74 |
if (attrs.hasOwnProperty('checklistComparator')){ |
|
75 |
if (attrs.checklistComparator[0] == '.') { |
|
76 |
var comparatorExpression = attrs.checklistComparator.substring(1); |
|
77 |
comparator = function (a, b) { |
|
78 |
return a[comparatorExpression] === b[comparatorExpression]; |
|
79 |
}; |
|
80 |
|
|
81 |
} else { |
|
82 |
comparator = $parse(attrs.checklistComparator)(scope.$parent); |
|
83 |
} |
|
84 |
} |
|
85 |
|
|
86 |
// watch UI checked change |
|
87 |
var unbindModel = scope.$watch(attrs.ngModel, function(newValue, oldValue) { |
|
88 |
if (newValue === oldValue) { |
|
89 |
return; |
|
90 |
} |
|
91 |
|
|
92 |
if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) { |
|
93 |
ngModelGetter.assign(scope, contains(checklistModelGetter(scope.$parent), getChecklistValue(), comparator)); |
|
94 |
return; |
|
95 |
} |
|
96 |
|
|
97 |
setValueInChecklistModel(getChecklistValue(), newValue); |
|
98 |
|
|
99 |
if (checklistChange) { |
|
100 |
checklistChange(scope); |
|
101 |
} |
|
102 |
}); |
|
103 |
|
|
104 |
// watches for value change of checklistValue |
|
105 |
var unbindCheckListValue = scope.$watch(getChecklistValue, function(newValue, oldValue) { |
|
106 |
if( newValue != oldValue && angular.isDefined(oldValue) && scope[attrs.ngModel] === true ) { |
|
107 |
var current = checklistModelGetter(scope.$parent); |
|
108 |
checklistModelGetter.assign(scope.$parent, remove(current, oldValue, comparator)); |
|
109 |
checklistModelGetter.assign(scope.$parent, add(current, newValue, comparator)); |
|
110 |
} |
|
111 |
}, true); |
|
112 |
|
|
113 |
var unbindDestroy = scope.$on('$destroy', destroy); |
|
114 |
|
|
115 |
function destroy() { |
|
116 |
unbindModel(); |
|
117 |
unbindCheckListValue(); |
|
118 |
unbindDestroy(); |
|
119 |
} |
|
120 |
|
|
121 |
function getChecklistValue() { |
|
122 |
return attrs.checklistValue ? $parse(attrs.checklistValue)(scope.$parent) : attrs.value; |
|
123 |
} |
|
124 |
|
|
125 |
function setValueInChecklistModel(value, checked) { |
|
126 |
var current = checklistModelGetter(scope.$parent); |
|
127 |
if (angular.isFunction(checklistModelGetter.assign)) { |
|
128 |
if (checked === true) { |
|
129 |
checklistModelGetter.assign(scope.$parent, add(current, value, comparator)); |
|
130 |
} else { |
|
131 |
checklistModelGetter.assign(scope.$parent, remove(current, value, comparator)); |
|
132 |
} |
|
133 |
} |
|
134 |
|
|
135 |
} |
|
136 |
|
|
137 |
// declare one function to be used for both $watch functions |
|
138 |
function setChecked(newArr, oldArr) { |
|
139 |
if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) { |
|
140 |
setValueInChecklistModel(getChecklistValue(), ngModelGetter(scope)); |
|
141 |
return; |
|
142 |
} |
|
143 |
ngModelGetter.assign(scope, contains(newArr, getChecklistValue(), comparator)); |
|
144 |
} |
|
145 |
|
|
146 |
// watch original model change |
|
147 |
// use the faster $watchCollection method if it's available |
|
148 |
if (angular.isFunction(scope.$parent.$watchCollection)) { |
|
149 |
scope.$parent.$watchCollection(checklistModel, setChecked); |
|
150 |
} else { |
|
151 |
scope.$parent.$watch(checklistModel, setChecked, true); |
|
152 |
} |
|
153 |
} |
|
154 |
|
|
155 |
return { |
|
156 |
restrict: 'A', |
|
157 |
priority: 1000, |
|
158 |
terminal: true, |
|
159 |
scope: true, |
|
160 |
compile: function(tElement, tAttrs) { |
|
161 |
|
|
162 |
if (!tAttrs.checklistValue && !tAttrs.value) { |
|
163 |
throw 'You should provide `value` or `checklist-value`.'; |
|
164 |
} |
|
165 |
|
|
166 |
// by default ngModel is 'checked', so we set it if not specified |
|
167 |
if (!tAttrs.ngModel) { |
|
168 |
// local scope var storing individual checkbox model |
|
169 |
tAttrs.$set("ngModel", "checked"); |
|
170 |
} |
|
171 |
|
|
172 |
return postLinkFn; |
|
173 |
} |
|
174 |
}; |
|
175 |
}]); |
modules/dnet-orgs-database-application/trunk/src/main/resources/templates/home.html | ||
---|---|---|
25 | 25 |
fieldset > legend { |
26 | 26 |
font-size: 1.2rem !important; |
27 | 27 |
} |
28 |
|
|
29 | 28 |
</style> |
30 | 29 |
|
31 | 30 |
|
... | ... | |
90 | 89 |
<script src="resources/js/bootstrap.min.js"></script> |
91 | 90 |
<script src="resources/js/angular.min.js"></script> |
92 | 91 |
<script src="resources/js/angular-route.min.js"></script> |
92 |
<script src='resources/js/checklist-model.js'></script> |
|
93 | 93 |
<script src="resources/js/organizations.js"></script> |
94 | 94 |
</body> |
95 | 95 |
|
Also available in: Unified diff
User Registration form