Form area and console
|
@ -25,22 +25,22 @@ body {
|
||||||
}
|
}
|
||||||
.alert.alert-success {
|
.alert.alert-success {
|
||||||
border-color: #4b9e39;
|
border-color: #4b9e39;
|
||||||
background-image: url(img/feedback-success-sign.svg);
|
background-image: url(img/feedback-success-sign.png);
|
||||||
background-color: #e4f1e1;
|
background-color: #e4f1e1;
|
||||||
}
|
}
|
||||||
.alert.alert-error {
|
.alert.alert-error {
|
||||||
border-color: #b91415;
|
border-color: #b91415;
|
||||||
background-image: url(img/feedback-error-sign.svg);
|
background-image: url(img/feedback-error-sign.png);
|
||||||
background-color: #f8e7e7;
|
background-color: #f8e7e7;
|
||||||
}
|
}
|
||||||
.alert.alert-warning {
|
.alert.alert-warning {
|
||||||
border-color: #f17528;
|
border-color: #f17528;
|
||||||
background-image: url(img/feedback-warning-sign.svg);
|
background-image: url(img/feedback-warning-sign.png);
|
||||||
background-color: #fef1e9;
|
background-color: #fef1e9;
|
||||||
}
|
}
|
||||||
.alert.alert-info {
|
.alert.alert-info {
|
||||||
border-color: #5994b2;
|
border-color: #5994b2;
|
||||||
background-image: url(img/feedback-info-sign.svg);
|
background-image: url(img/feedback-info-sign.png);
|
||||||
background-color: #e4f3fa;
|
background-color: #e4f3fa;
|
||||||
}
|
}
|
||||||
/* Header */
|
/* Header */
|
||||||
|
@ -65,9 +65,39 @@ body {
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
max-width: 1170px;
|
max-width: 1170px;
|
||||||
}
|
}
|
||||||
|
.header.rcue .navbar.primary .select-rcue {
|
||||||
|
font-size: 0.76923076923077em;
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-top: 0.7em;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #555a5e;
|
||||||
|
background-image: none;
|
||||||
|
background-image: url(img/sprite-arrow-down.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right -26px;
|
||||||
|
border: 1px solid #676c6e;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.header.rcue .navbar.primary .select-rcue:hover {
|
||||||
|
border-color: #7e8385;
|
||||||
|
}
|
||||||
|
.header.rcue .navbar.primary .select-rcue select {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.header.rcue .navbar.primary .select-rcue select:-moz-focusring {
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: 0 0 0 #fff;
|
||||||
|
}
|
||||||
|
.header.rcue .navbar.primary .select-rcue select option {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #333;
|
||||||
|
padding: 0.36363636363636em 0.90909090909091em;
|
||||||
|
}
|
||||||
.header.rcue .navbar.primary .nav > li {
|
.header.rcue .navbar.primary .nav > li {
|
||||||
/*
|
/*
|
||||||
.dropdown {
|
.dropdown {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 0.53846153846154em;
|
margin-left: 0.53846153846154em;
|
||||||
margin-top: 0.46153846153846em;
|
margin-top: 0.46153846153846em;
|
||||||
|
@ -402,7 +432,7 @@ table + .feedback.inline.warning {
|
||||||
.tooltip-box {
|
.tooltip-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
background-image: url("img/tooltip-box-arrow-right-up.svg");
|
background-image: url("img/tooltip-box-arrow-right-up.png");
|
||||||
background-position: right top;
|
background-position: right top;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
|
|
|
@ -37,25 +37,25 @@ body {
|
||||||
|
|
||||||
&.alert-success {
|
&.alert-success {
|
||||||
border-color: #4b9e39;
|
border-color: #4b9e39;
|
||||||
background-image: url(img/feedback-success-sign.svg);
|
background-image: url(img/feedback-success-sign.png);
|
||||||
background-color: #e4f1e1;
|
background-color: #e4f1e1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.alert-error {
|
&.alert-error {
|
||||||
border-color: #b91415;
|
border-color: #b91415;
|
||||||
background-image: url(img/feedback-error-sign.svg);
|
background-image: url(img/feedback-error-sign.png);
|
||||||
background-color: #f8e7e7;
|
background-color: #f8e7e7;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.alert-warning {
|
&.alert-warning {
|
||||||
border-color: #f17528;
|
border-color: #f17528;
|
||||||
background-image: url(img/feedback-warning-sign.svg);
|
background-image: url(img/feedback-warning-sign.png);
|
||||||
background-color: #fef1e9;
|
background-color: #fef1e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.alert-info {
|
&.alert-info {
|
||||||
border-color: #5994b2;
|
border-color: #5994b2;
|
||||||
background-image: url(img/feedback-info-sign.svg);
|
background-image: url(img/feedback-info-sign.png);
|
||||||
background-color: #e4f3fa;
|
background-color: #e4f3fa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,41 @@ body {
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
max-width: 1170px;
|
max-width: 1170px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.select-rcue {
|
||||||
|
font-size: 0.76923076923077em;
|
||||||
|
margin-left: 1em;
|
||||||
|
margin-top: 0.7em;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #555a5e;
|
||||||
|
background-image: none;
|
||||||
|
background-image: url(img/sprite-arrow-down.png);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right -26px;
|
||||||
|
border: 1px solid #676c6e;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: #7e8385;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:-moz-focusring {
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: 0 0 0 #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
option {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #333;
|
||||||
|
padding: 0.36363636363636em 0.90909090909091em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.nav > li {
|
.nav > li {
|
||||||
|
|
||||||
|
@ -161,7 +196,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
.dropdown {
|
.dropdown {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 0.53846153846154em;
|
margin-left: 0.53846153846154em;
|
||||||
margin-top: 0.46153846153846em;
|
margin-top: 0.46153846153846em;
|
||||||
|
@ -488,7 +523,7 @@ table {
|
||||||
.tooltip-box {
|
.tooltip-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
background-image: url("img/tooltip-box-arrow-right-up.svg");
|
background-image: url("img/tooltip-box-arrow-right-up.png");
|
||||||
background-position: right top;
|
background-position: right top;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
|
@ -778,4 +813,4 @@ table.list {
|
||||||
border: none;
|
border: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,29 +319,29 @@ button.primary:focus,
|
||||||
background-position: 1.27272727272727em 1.63636363636364em;
|
background-position: 1.27272727272727em 1.63636363636364em;
|
||||||
}
|
}
|
||||||
.feedback.error {
|
.feedback.error {
|
||||||
background-image: url(img/feedback-error-arrow-down.svg);
|
background-image: url(img/feedback-error-arrow-down.png);
|
||||||
}
|
}
|
||||||
.feedback.error p {
|
.feedback.error p {
|
||||||
border-color: #b91415;
|
border-color: #b91415;
|
||||||
background-image: url(img/feedback-error-sign.svg);
|
background-image: url(img/feedback-error-sign.png);
|
||||||
background-color: #f8e7e7;
|
background-color: #f8e7e7;
|
||||||
}
|
}
|
||||||
.feedback.success {
|
.feedback.success {
|
||||||
background-image: url(img/feedback-success-arrow-down.svg);
|
background-image: url(img/feedback-success-arrow-down.png);
|
||||||
}
|
}
|
||||||
.feedback.success p {
|
.feedback.success p {
|
||||||
border-color: #4b9e39;
|
border-color: #4b9e39;
|
||||||
background-image: url(img/feedback-success-sign.svg);
|
background-image: url(img/feedback-success-sign.png);
|
||||||
background-color: #e4f1e1;
|
background-color: #e4f1e1;
|
||||||
}
|
}
|
||||||
.feedback.warning p {
|
.feedback.warning p {
|
||||||
border-color: #f17528;
|
border-color: #f17528;
|
||||||
background-image: url(img/feedback-warning-sign.svg);
|
background-image: url(img/feedback-warning-sign.png);
|
||||||
background-color: #fef1e9;
|
background-color: #fef1e9;
|
||||||
}
|
}
|
||||||
.feedback.info p {
|
.feedback.info p {
|
||||||
border-color: #5994b2;
|
border-color: #5994b2;
|
||||||
background-image: url(img/feedback-info-sign.svg);
|
background-image: url(img/feedback-info-sign.png);
|
||||||
background-color: #e4f3fa;
|
background-color: #e4f3fa;
|
||||||
}
|
}
|
||||||
.feedback.inline {
|
.feedback.inline {
|
||||||
|
|
|
@ -358,21 +358,21 @@ button.primary,
|
||||||
}
|
}
|
||||||
|
|
||||||
&.error {
|
&.error {
|
||||||
background-image: url(img/feedback-error-arrow-down.svg);
|
background-image: url(img/feedback-error-arrow-down.png);
|
||||||
|
|
||||||
p {
|
p {
|
||||||
border-color: #b91415;
|
border-color: #b91415;
|
||||||
background-image: url(img/feedback-error-sign.svg);
|
background-image: url(img/feedback-error-sign.png);
|
||||||
background-color: #f8e7e7;
|
background-color: #f8e7e7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.success {
|
&.success {
|
||||||
background-image: url(img/feedback-success-arrow-down.svg);
|
background-image: url(img/feedback-success-arrow-down.png);
|
||||||
|
|
||||||
p {
|
p {
|
||||||
border-color: #4b9e39;
|
border-color: #4b9e39;
|
||||||
background-image: url(img/feedback-success-sign.svg);
|
background-image: url(img/feedback-success-sign.png);
|
||||||
background-color: #e4f1e1;
|
background-color: #e4f1e1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +381,7 @@ button.primary,
|
||||||
|
|
||||||
p {
|
p {
|
||||||
border-color: #f17528;
|
border-color: #f17528;
|
||||||
background-image: url(img/feedback-warning-sign.svg);
|
background-image: url(img/feedback-warning-sign.png);
|
||||||
background-color: #fef1e9;
|
background-color: #fef1e9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@ button.primary,
|
||||||
|
|
||||||
p {
|
p {
|
||||||
border-color: #5994b2;
|
border-color: #5994b2;
|
||||||
background-image: url(img/feedback-info-sign.svg);
|
background-image: url(img/feedback-info-sign.png);
|
||||||
background-color: #e4f3fa;
|
background-color: #e4f3fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 162 B |
|
@ -40,7 +40,6 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
|
||||||
};
|
};
|
||||||
$scope.showNav = function() {
|
$scope.showNav = function() {
|
||||||
var show = Current.realms.length > 0;
|
var show = Current.realms.length > 0;
|
||||||
console.log('Show dropdown? ' + show);
|
|
||||||
return Auth.loggedIn && show;
|
return Auth.loggedIn && show;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -137,11 +136,12 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, $ht
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.cancel = function() {
|
$scope.cancel = function() {
|
||||||
$location.url("/realms");
|
//$location.url("/realms");
|
||||||
|
window.history.back();
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.remove = function() {
|
$scope.remove = function() {
|
||||||
Dialog.confirmDelete($scope.realm.name, 'realm', function() {
|
Dialog.confirmDelete($scope.realm.realm, 'realm', function() {
|
||||||
Realm.remove($scope.realm, function() {
|
Realm.remove($scope.realm, function() {
|
||||||
Current.realms = Realm.get();
|
Current.realms = Realm.get();
|
||||||
$location.url("/realms");
|
$location.url("/realms");
|
||||||
|
@ -200,9 +200,10 @@ module.controller('RealmRequiredCredentialsCtrl', function($scope, Realm, realm,
|
||||||
module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications) {
|
module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications) {
|
||||||
console.log('RealmTokenDetailCtrl');
|
console.log('RealmTokenDetailCtrl');
|
||||||
|
|
||||||
$scope.realm = { id : realm.id, realm : realm.realm, social : realm.social, tokenLifespan : realm.tokenLifespan, accessCodeLifespan : realm.accessCodeLifespan };
|
$scope.realm = { id : realm.id, realm : realm.realm, social : realm.social, tokenLifespan : realm.tokenLifespan, accessCodeLifespan : realm.accessCodeLifespan , accessCodeLifespanUserAction : realm.accessCodeLifespanUserAction };
|
||||||
$scope.realm.tokenLifespanUnit = 'Seconds';
|
$scope.realm.tokenLifespanUnit = 'Seconds';
|
||||||
$scope.realm.accessCodeLifespanUnit = 'Seconds';
|
$scope.realm.accessCodeLifespanUnit = 'Seconds';
|
||||||
|
$scope.realm.accessCodeLifespanUserActionUnit = 'Seconds';
|
||||||
|
|
||||||
var oldCopy = angular.copy($scope.realm);
|
var oldCopy = angular.copy($scope.realm);
|
||||||
$scope.changed = false;
|
$scope.changed = false;
|
||||||
|
@ -218,6 +219,7 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http,
|
||||||
var realmCopy = angular.copy($scope.realm);
|
var realmCopy = angular.copy($scope.realm);
|
||||||
delete realmCopy["tokenLifespanUnit"];
|
delete realmCopy["tokenLifespanUnit"];
|
||||||
delete realmCopy["accessCodeLifespanUnit"];
|
delete realmCopy["accessCodeLifespanUnit"];
|
||||||
|
delete realmCopy["accessCodeLifespanUserActionUnit"];
|
||||||
if ($scope.realm.tokenLifespanUnit == 'Minutes') {
|
if ($scope.realm.tokenLifespanUnit == 'Minutes') {
|
||||||
realmCopy.tokenLifespan = $scope.realm.tokenLifespan * 60;
|
realmCopy.tokenLifespan = $scope.realm.tokenLifespan * 60;
|
||||||
} else if ($scope.realm.tokenLifespanUnit == 'Hours') {
|
} else if ($scope.realm.tokenLifespanUnit == 'Hours') {
|
||||||
|
@ -232,6 +234,13 @@ module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http,
|
||||||
} else if ($scope.realm.accessCodeLifespanUnit == 'Days') {
|
} else if ($scope.realm.accessCodeLifespanUnit == 'Days') {
|
||||||
realmCopy.accessCodeLifespan = $scope.realm.accessCodeLifespan * 60 * 60 * 24;
|
realmCopy.accessCodeLifespan = $scope.realm.accessCodeLifespan * 60 * 60 * 24;
|
||||||
}
|
}
|
||||||
|
if ($scope.realm.accessCodeLifespanUserActionUnit == 'Minutes') {
|
||||||
|
realmCopy.accessCodeLifespanUserAction = $scope.realm.accessCodeLifespanUserAction * 60;
|
||||||
|
} else if ($scope.realm.accessCodeLifespanUserActionUnit == 'Hours') {
|
||||||
|
realmCopy.accessCodeLifespanUserAction = $scope.realm.accessCodeLifespanUserAction * 60 * 60;
|
||||||
|
} else if ($scope.realm.accessCodeLifespanUserActionUnit == 'Days') {
|
||||||
|
realmCopy.accessCodeLifespanUserAction = $scope.realm.accessCodeLifespanUserAction * 60 * 60 * 24;
|
||||||
|
}
|
||||||
$scope.changed = false;
|
$scope.changed = false;
|
||||||
Realm.update(realmCopy, function () {
|
Realm.update(realmCopy, function () {
|
||||||
$location.url("/realms/" + realm.id + "/token-settings");
|
$location.url("/realms/" + realm.id + "/token-settings");
|
||||||
|
|
|
@ -134,7 +134,7 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
|
||||||
$scope.user = angular.copy(user);
|
$scope.user = angular.copy(user);
|
||||||
$scope.create = !user.username;
|
$scope.create = !user.username;
|
||||||
|
|
||||||
$scope.changed = $scope.create;
|
$scope.changed = false; // $scope.create;
|
||||||
|
|
||||||
$scope.$watch('user', function() {
|
$scope.$watch('user', function() {
|
||||||
if (!angular.equals($scope.user, user)) {
|
if (!angular.equals($scope.user, user)) {
|
||||||
|
@ -176,7 +176,7 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, $locatio
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.remove = function() {
|
$scope.remove = function() {
|
||||||
Dialog.confirmDelete($scope.user.userId, 'user', function() {
|
Dialog.confirmDelete($scope.user.username, 'user', function() {
|
||||||
$scope.user.$remove({
|
$scope.user.$remove({
|
||||||
realm : realm.id,
|
realm : realm.id,
|
||||||
userId : $scope.user.username
|
userId : $scope.user.username
|
||||||
|
|
|
@ -970,8 +970,8 @@ dialogModule.provider("$dialog", function(){
|
||||||
transitionClass: 'fade',
|
transitionClass: 'fade',
|
||||||
triggerClass: 'in',
|
triggerClass: 'in',
|
||||||
resolve:{},
|
resolve:{},
|
||||||
backdropFade: false,
|
backdropFade: true,
|
||||||
dialogFade:false,
|
dialogFade: true,
|
||||||
keyboard: true, // close with esc key
|
keyboard: true, // close with esc key
|
||||||
backdropClick: true // only in conjunction with backdrop=true
|
backdropClick: true // only in conjunction with backdrop=true
|
||||||
/* other options: template, templateUrl, controller */
|
/* other options: template, templateUrl, controller */
|
||||||
|
@ -1027,6 +1027,7 @@ dialogModule.provider("$dialog", function(){
|
||||||
this.modalEl.addClass(options.transitionClass);
|
this.modalEl.addClass(options.transitionClass);
|
||||||
this.modalEl.removeClass(options.triggerClass);
|
this.modalEl.removeClass(options.triggerClass);
|
||||||
}
|
}
|
||||||
|
this.modalEl.css("display", "block"); /* FIXME: For BS 3.x support */
|
||||||
|
|
||||||
this.handledEscapeKey = function(e) {
|
this.handledEscapeKey = function(e) {
|
||||||
if (e.which === 27) {
|
if (e.which === 27) {
|
||||||
|
@ -2997,6 +2998,8 @@ angular.module("template/datepicker/datepicker.html", []).run(["$templateCache",
|
||||||
|
|
||||||
angular.module("template/dialog/message.html", []).run(["$templateCache", function($templateCache) {
|
angular.module("template/dialog/message.html", []).run(["$templateCache", function($templateCache) {
|
||||||
$templateCache.put("template/dialog/message.html",
|
$templateCache.put("template/dialog/message.html",
|
||||||
|
"<div class=\"modal-dialog\">\n" +
|
||||||
|
"<div class=\"modal-content\">\n" +
|
||||||
"<div class=\"modal-header\">\n" +
|
"<div class=\"modal-header\">\n" +
|
||||||
" <h3>{{ title }}</h3>\n" +
|
" <h3>{{ title }}</h3>\n" +
|
||||||
"</div>\n" +
|
"</div>\n" +
|
||||||
|
@ -3006,6 +3009,8 @@ angular.module("template/dialog/message.html", []).run(["$templateCache", functi
|
||||||
"<div class=\"modal-footer\">\n" +
|
"<div class=\"modal-footer\">\n" +
|
||||||
" <button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=\"btn\" ng-class=\"btn.cssClass\">{{ btn.label }}</button>\n" +
|
" <button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=\"btn\" ng-class=\"btn.cssClass\">{{ btn.label }}</button>\n" +
|
||||||
"</div>\n" +
|
"</div>\n" +
|
||||||
|
"</div>\n" +
|
||||||
|
"</div>\n" +
|
||||||
"");
|
"");
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
|
@ -104,10 +104,9 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="form-actions" data-ng-show="create">
|
<div class="form-actions" data-ng-show="create">
|
||||||
<button type="submit" data-ng-click="save()" class="primary">Save
|
<button type="submit" data-ng-click="save()" data-ng-show="changed" class="primary">Save
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" data-ng-click="cancel()" data-ng-click="cancel()"
|
<button type="submit" data-ng-click="cancel()">Cancel
|
||||||
data-ng-show="changed">Cancel
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -116,7 +115,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" data-ng-click="reset()" data-ng-show="changed">Clear changes
|
<button type="submit" data-ng-click="reset()" data-ng-show="changed">Clear changes
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" data-ng-click="remove()" class="destructive">
|
<button type="submit" data-ng-click="remove()" class="destructive" data-ng-hide="changed">
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,14 +16,15 @@
|
||||||
<div class="feedback info inline" data-ng-show="!applications || applications.length == 0">
|
<div class="feedback info inline" data-ng-show="!applications || applications.length == 0">
|
||||||
<p><strong>You have not configured applications.</strong> <a class="button" href="#/create/application/{{realm.id}}">Add Application</a></p>
|
<p><strong>You have not configured applications.</strong> <a class="button" href="#/create/application/{{realm.id}}">Add Application</a></p>
|
||||||
</div>
|
</div>
|
||||||
<table>
|
<table data-ng-hide="applications.length == 0">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="rcue-table-actions" colspan="3">
|
<th class="rcue-table-actions" colspan="3">
|
||||||
<div class="search-comp clearfix">
|
<div class="search-comp clearfix">
|
||||||
<input type="text" placeholder="Search..." class="search">
|
<input type="text" placeholder="Search..." class="search"
|
||||||
<button class="icon-search tooltipRightTrigger"
|
onkeyup="if(event.keyCode == 13){$(this).next('button').click();}">
|
||||||
data-original-title="Search by application name.">
|
<button class="icon-search" tooltip-placement="right"
|
||||||
|
tooltip="Search by application name.">
|
||||||
Icon: search
|
Icon: search
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr data-ng-show="applications.length > 0">
|
||||||
<th>Application Name</th>
|
<th>Application Name</th>
|
||||||
<th>Enabled</th>
|
<th>Enabled</th>
|
||||||
<th>Base URL</th>
|
<th>Base URL</th>
|
||||||
|
@ -58,7 +59,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="feedback warning inline">
|
<div class="feedback warning inline" data-ng-show="search && applications.length == 0">
|
||||||
<p><strong>Your search returned no results.</strong><br>Try modifying the query and try again.</p>
|
<p><strong>Your search returned no results.</strong><br>Try modifying the query and try again.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
<th class="rcue-table-actions" colspan="2">
|
<th class="rcue-table-actions" colspan="2">
|
||||||
<div class="search-comp clearfix">
|
<div class="search-comp clearfix">
|
||||||
<input type="text" placeholder="Search..." class="search">
|
<input type="text" placeholder="Search..." class="search">
|
||||||
<button class="icon-search tooltipRightTrigger"
|
<button class="icon-search" tooltip-placement="right"
|
||||||
data-original-title="Search by role name.">
|
tooltip="Search by role name.">
|
||||||
Icon: search
|
Icon: search
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -35,8 +35,8 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-buttons">
|
<div class="middle-buttons">
|
||||||
<button type="submit" ng-click="addRealmRole()" data-original-title="Move right" class="tooltipRightTrigger"><span class="icon-arrow-right">Move right</span></button>
|
<button type="submit" ng-click="addRealmRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
|
||||||
<button type="submit" ng-click="deleteRealmRole()" data-original-title="Move left" class="tooltipRightTrigger"><span class="icon-arrow-left">Move left</span></button>
|
<button type="submit" ng-click="deleteRealmRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="select-title">
|
<div class="select-title">
|
||||||
<label for="assigned">Assigned Roles</label>
|
<label for="assigned">Assigned Roles</label>
|
||||||
|
@ -57,11 +57,12 @@
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="select-rcue">
|
<div class="select-rcue">
|
||||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in applications">
|
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="targetApp" ng-options="a.name for a in applications">
|
||||||
|
<option value="" selected> Select an Application </option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group" ng-show="targetApp">
|
||||||
<div class="controls changing-selectors application">
|
<div class="controls changing-selectors application">
|
||||||
<div class="select-title">
|
<div class="select-title">
|
||||||
<label for="app-available">Available Roles</label>
|
<label for="app-available">Available Roles</label>
|
||||||
|
@ -72,8 +73,8 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-buttons">
|
<div class="middle-buttons">
|
||||||
<button type="submit" ng-click="addApplicationRole()" data-original-title="Move right" class="tooltipRightTrigger"><span class="icon-arrow-right">Move right</span></button>
|
<button type="submit" ng-click="addApplicationRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
|
||||||
<button type="submit" ng-click="deleteApplicationRole()" data-original-title="Move left" class="tooltipRightTrigger"><span class="icon-arrow-left">Move left</span></button>
|
<button type="submit" ng-click="deleteApplicationRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="select-title">
|
<div class="select-title">
|
||||||
<label for="app-assigned">Assigned Roles</label>
|
<label for="app-assigned">Assigned Roles</label>
|
||||||
|
|
|
@ -119,8 +119,7 @@
|
||||||
<div class="form-actions" data-ng-show="createRealm">
|
<div class="form-actions" data-ng-show="createRealm">
|
||||||
<button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
|
<button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" data-ng-click="cancel()" data-ng-click="cancel()"
|
<button type="submit" data-ng-click="cancel()">Cancel
|
||||||
data-ng-show="changed">Cancel
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,20 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group input-select">
|
||||||
|
<label for="accessCodeLifespanUserAction">Access code user action lifespan</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" data-ng-model="realm.accessCodeLifespanUserAction" id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction" class="tiny">
|
||||||
|
<div class="select-rcue">
|
||||||
|
<select name="accessCodeLifespanUserActionUnit" data-ng-model="realm.accessCodeLifespanUserActionUnit">
|
||||||
|
<option data-ng-selected="!realm.accessCodeLifespanUserActionUnit">Seconds</option>
|
||||||
|
<option>Minutes</option>
|
||||||
|
<option>Hours</option>
|
||||||
|
<option>Days</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
|
<button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
|
||||||
|
|
|
@ -36,8 +36,8 @@
|
||||||
<th class="rcue-table-actions" colspan="2">
|
<th class="rcue-table-actions" colspan="2">
|
||||||
<div class="search-comp clearfix">
|
<div class="search-comp clearfix">
|
||||||
<input type="text" placeholder="Search..." class="search">
|
<input type="text" placeholder="Search..." class="search">
|
||||||
<button class="icon-search tooltipRightTrigger"
|
<button class="icon-search" tooltip-placement="right"
|
||||||
data-original-title="Search by role name.">
|
tooltip="Search by role name.">
|
||||||
Icon: search
|
Icon: search
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<ul class="rcue-tabs" >
|
<ul class="rcue-tabs" >
|
||||||
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}">Attributes</a></li>
|
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}">Attributes</a></li>
|
||||||
<li><a href="#">Credentials</a></li>
|
<li><a href="#">Credentials</a></li>
|
||||||
<li class="active"><a href="#">Role Mappings</a></li>
|
<li class="active"><a href="#/realms/{{realm.id}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
@ -32,8 +32,8 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-buttons">
|
<div class="middle-buttons">
|
||||||
<button type="submit" ng-click="addRealmRole()" data-original-title="Move right" class="tooltipRightTrigger"><span class="icon-arrow-right">Move right</span></button>
|
<button type="submit" ng-click="addRealmRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
|
||||||
<button type="submit" ng-click="deleteRealmRole()" data-original-title="Move left" class="tooltipRightTrigger"><span class="icon-arrow-left">Move left</span></button>
|
<button type="submit" ng-click="deleteRealmRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="select-title">
|
<div class="select-title">
|
||||||
<label for="assigned">Assigned Roles</label>
|
<label for="assigned">Assigned Roles</label>
|
||||||
|
@ -54,6 +54,7 @@
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<div class="select-rcue">
|
<div class="select-rcue">
|
||||||
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications">
|
<select id="applications" name="applications" ng-change="changeApplication()" ng-model="application" ng-options="a.name for a in applications">
|
||||||
|
<option value="" selected> Select an Application...</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,8 +70,8 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle-buttons">
|
<div class="middle-buttons">
|
||||||
<button type="submit" ng-click="addApplicationRole()" data-original-title="Move right" class="tooltipRightTrigger"><span class="icon-arrow-right">Move right</span></button>
|
<button type="submit" ng-click="addApplicationRole()" tooltip="Move right" tooltip-placement="right"><span class="icon-arrow-right">Move right</span></button>
|
||||||
<button type="submit" ng-click="deleteApplicationRole()" data-original-title="Move left" class="tooltipRightTrigger"><span class="icon-arrow-left">Move left</span></button>
|
<button type="submit" ng-click="deleteApplicationRole()" tooltip="Move left" tooltip-placement="right"><span class="icon-arrow-left">Move left</span></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="select-title">
|
<div class="select-title">
|
||||||
<label for="assigned-app">Assigned Roles</label>
|
<label for="assigned-app">Assigned Roles</label>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="top-nav" data-ng-show="!create">
|
<div class="top-nav" data-ng-show="!create">
|
||||||
<ul class="rcue-tabs" >
|
<ul class="rcue-tabs" >
|
||||||
<li class="active"><a href="#">Attributes</a></li>
|
<li class="active"><a href="#/realms/{{realm.id}}/users/{{user.username}}">Attributes</a></li>
|
||||||
<li><a href="#">Credentials</a></li>
|
<li><a href="#">Credentials</a></li>
|
||||||
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
|
<li><a href="#/realms/{{realm.id}}/users/{{user.username}}/role-mappings">Role Mappings</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -67,10 +67,9 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="form-actions" data-ng-show="create">
|
<div class="form-actions" data-ng-show="create">
|
||||||
<button type="submit" data-ng-click="save()" class="primary">Save
|
<button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" data-ng-click="cancel()" data-ng-click="cancel()"
|
<button type="submit" data-ng-click="cancel()">Cancel
|
||||||
data-ng-show="changed">Cancel
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -79,7 +78,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" data-ng-click="reset()" data-ng-show="changed">Clear changes
|
<button type="submit" data-ng-click="reset()" data-ng-show="changed">Clear changes
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" data-ng-click="remove()" class="destructive">
|
<button type="submit" data-ng-click="remove()" class="destructive" data-ng-hide="changed">
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
<tr>
|
<tr>
|
||||||
<th class="rcue-table-actions" colspan="4">
|
<th class="rcue-table-actions" colspan="4">
|
||||||
<div class="search-comp clearfix">
|
<div class="search-comp clearfix">
|
||||||
<input type="text" placeholder="Search..." data-ng-model="search" class="search">
|
<input type="text" placeholder="Search..." data-ng-model="search" class="search"
|
||||||
<button data-ng-click="searchQuery()"
|
onkeyup="if(event.keyCode == 13){$(this).next('button').click();}">
|
||||||
class="icon-search tooltipRightTrigger"
|
<button data-ng-click="searchQuery()" type="submit"
|
||||||
data-original-title="Search by full name, last name, email, or username.">
|
class="icon-search" tooltip-placement="right"
|
||||||
|
tooltip="Search by full name, last name, email, or username.">
|
||||||
Icon: search
|
Icon: search
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<tr data-ng-show="users && search">
|
<tr data-ng-show="users.length > 0">
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Last Name</th>
|
<th>Last Name</th>
|
||||||
<th>First Name</th>
|
<th>First Name</th>
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div class="feedback warning inline">
|
<div class="feedback warning inline" data-ng-show="users.length == 0">
|
||||||
<p><strong>Your search returned no results.</strong><br>Try modifying the query and try again.</p>
|
<p><strong>Your search returned no results.</strong><br>Try modifying the query and try again.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -104,7 +104,7 @@ public class RealmRepresentation {
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isAccountManagement() {
|
public Boolean getAccountManagement() {
|
||||||
return accountManagement;
|
return accountManagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,24 +51,21 @@ body {
|
||||||
}
|
}
|
||||||
.rcue-login-register .background-area .section {
|
.rcue-login-register .background-area .section {
|
||||||
float: left;
|
float: left;
|
||||||
padding: 1.5em 4.5em 1.5em 4.6em;
|
padding: 0 4.5em 0 4.6em;
|
||||||
width: auto;
|
width: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
.rcue-login-register .background-area .separator .section {
|
||||||
|
padding-top: 1.5em;
|
||||||
|
padding-bottom: 1.5em;
|
||||||
|
}
|
||||||
.rcue-login-register .background-area .section h3 {
|
.rcue-login-register .background-area .section h3 {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.rcue-login-register .background-area .section:first-child {
|
.rcue-login-register .background-area .section:first-child {
|
||||||
padding-right: 4.5em;
|
padding-right: 4.5em;
|
||||||
}
|
}
|
||||||
/*
|
.rcue-login-register .form-area.separator {
|
||||||
.rcue-login-register .form-area {
|
|
||||||
background-image: url(img/login-register-separator.png);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 40.2em center;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
.rcue-login-register.reset .form-area {
|
|
||||||
background-image: url(img/login-register-separator.png);
|
background-image: url(img/login-register-separator.png);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 43.2em center;
|
background-position: 43.2em center;
|
||||||
|
@ -96,9 +93,7 @@ body {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
.rcue-login-register label {
|
.rcue-login-register label {
|
||||||
width: 6.07142857142857em;
|
width: 8.21428571428571em;
|
||||||
/* 85px */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
.rcue-login-register label.two-lines {
|
.rcue-login-register label.two-lines {
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -114,12 +109,8 @@ body {
|
||||||
.rcue-login-register form > div.aside-btn {
|
.rcue-login-register form > div.aside-btn {
|
||||||
float: left;
|
float: left;
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
margin-left: 7.72727272727273em;
|
margin-left: 10.4545454545454em;
|
||||||
/* 85px */
|
|
||||||
|
|
||||||
margin-top: 0.90909090909091em;
|
margin-top: 0.90909090909091em;
|
||||||
/* 10px */
|
|
||||||
|
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.rcue-login-register form > div.aside-btn label {
|
.rcue-login-register form > div.aside-btn label {
|
||||||
|
@ -291,19 +282,13 @@ a.zocial:before {
|
||||||
color: #0099D3;
|
color: #0099D3;
|
||||||
}
|
}
|
||||||
/* Forgot Password page */
|
/* Forgot Password page */
|
||||||
.rcue-login-register.reset .background-area .section {
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
.rcue-login-register.reset .background-area .section.app-form {
|
.rcue-login-register.reset .background-area .section.app-form {
|
||||||
width: 43.2em;
|
width: 43.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcue-login-register.oauth .form-actions {
|
.rcue-login-register.oauth .form-actions {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
margin-top: 2em;
|
margin-top: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rcue-login-register .background-area .content-area {
|
.rcue-login-register .background-area .content-area {
|
||||||
width: 50em;
|
width: 50em;
|
||||||
}
|
}
|
||||||
|
@ -360,9 +345,6 @@ a.zocial:before {
|
||||||
line-height: 1.3em;
|
line-height: 1.3em;
|
||||||
margin-bottom: 1.81818181818182em;
|
margin-bottom: 1.81818181818182em;
|
||||||
}
|
}
|
||||||
.rcue-login-register.reset label {
|
|
||||||
width: 8.21428571428571em;
|
|
||||||
}
|
|
||||||
.rcue-login-register.totp {
|
.rcue-login-register.totp {
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,6 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<#elseif section = "info" >
|
<#elseif section = "info" >
|
||||||
<p><a href="saas-login.html">« Back to the Login</a></p>
|
<p><a href="#">« Back to Login</a></p>
|
||||||
</#if>
|
</#if>
|
||||||
</@layout.registrationLayout>
|
</@layout.registrationLayout>
|
|
@ -91,7 +91,7 @@ public class RealmManager {
|
||||||
realm.updateDefaultRoles(rep.getDefaultRoles());
|
realm.updateDefaultRoles(rep.getDefaultRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep.isAccountManagement()) {
|
if (rep.getAccountManagement() != null && rep.getAccountManagement()) {
|
||||||
enableAccountManagement(realm);
|
enableAccountManagement(realm);
|
||||||
} else {
|
} else {
|
||||||
disableAccountManagement(realm);
|
disableAccountManagement(realm);
|
||||||
|
@ -253,7 +253,7 @@ public class RealmManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rep.isAccountManagement() != null && rep.isAccountManagement()) {
|
if (rep.getAccountManagement() != null && rep.getAccountManagement()) {
|
||||||
enableAccountManagement(newRealm);
|
enableAccountManagement(newRealm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,10 @@ public class KeycloakServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
new ApplianceBootstrap().bootstrap(session);
|
new ApplianceBootstrap().bootstrap(session);
|
||||||
|
|
||||||
|
// No need to require admin to change password as this server is for dev/test
|
||||||
|
manager.getRealm(Constants.ADMIN_REALM).getUser("admin").removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||||
|
|
||||||
session.getTransaction().commit();
|
session.getTransaction().commit();
|
||||||
} finally {
|
} finally {
|
||||||
session.close();
|
session.close();
|
||||||
|
|
22
ui/pom.xml
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<project>
|
|
||||||
<parent>
|
|
||||||
<artifactId>keycloak-parent</artifactId>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<version>1.0-alpha-1</version>
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>keycloak-ui</artifactId>
|
|
||||||
<name>Keycloak UI</name>
|
|
||||||
<description/>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.resteasy</groupId>
|
|
||||||
<artifactId>jaxrs-api</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
|
@ -1,230 +0,0 @@
|
||||||
package org.keycloak.ui.example;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import javax.ws.rs.ApplicationPath;
|
|
||||||
import javax.ws.rs.Consumes;
|
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.PUT;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
|
||||||
|
|
||||||
@ApplicationPath("ui/api")
|
|
||||||
@Path("")
|
|
||||||
public class Admin extends javax.ws.rs.core.Application {
|
|
||||||
|
|
||||||
private static Map<String, Application> applications = new HashMap<String, Application>();
|
|
||||||
|
|
||||||
private static Map<String, Realm> realms = new HashMap<String, Realm>();
|
|
||||||
|
|
||||||
private static Map<String, List<User>> users = new HashMap<String, List<User>>();
|
|
||||||
|
|
||||||
private static Map<Id, List<String>> roles = new HashMap<Id, List<String>>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
Realm realm = new Realm();
|
|
||||||
realm.setId(UUID.randomUUID().toString());
|
|
||||||
realm.setName("Test realm");
|
|
||||||
realm.setEnabled(true);
|
|
||||||
realm.setRoles(new String[] { "admin", "user" });
|
|
||||||
realms.put(realm.getId(), realm);
|
|
||||||
|
|
||||||
User user = new User();
|
|
||||||
user.setUserId("user");
|
|
||||||
user.setPassword("password");
|
|
||||||
|
|
||||||
List<User> l = new LinkedList<User>();
|
|
||||||
l.add(user);
|
|
||||||
|
|
||||||
users.put(realm.getId(), l);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DELETE
|
|
||||||
@Path("applications/{id}")
|
|
||||||
public void deleteApplication(@PathParam("id") String id) {
|
|
||||||
applications.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DELETE
|
|
||||||
@Path("realms/{id}")
|
|
||||||
public void deleteRealm(@PathParam("id") String id) {
|
|
||||||
realms.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("applications/{id}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public Application getApplication(@PathParam("id") String id) {
|
|
||||||
return applications.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("applications")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public List<Application> getApplications() {
|
|
||||||
return new LinkedList<Application>(applications.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("realms/{id}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public Realm getRealm(@PathParam("id") String id) {
|
|
||||||
return realms.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("realms")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public List<Realm> getRealms() {
|
|
||||||
return new LinkedList<Realm>(realms.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
|
||||||
@Path("applications")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public Response save(Application application) {
|
|
||||||
String id = UUID.randomUUID().toString();
|
|
||||||
application.setId(id);
|
|
||||||
applications.put(id, application);
|
|
||||||
return Response.created(URI.create("/applications/" + id)).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
|
||||||
@Path("realms")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public Response save(Realm realm) {
|
|
||||||
String id = UUID.randomUUID().toString();
|
|
||||||
realm.setId(id);
|
|
||||||
realms.put(id, realm);
|
|
||||||
return Response.created(URI.create("/realms/" + id)).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@PUT
|
|
||||||
@Path("applications/{id}")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public void save(@PathParam("id") String id, Application application) {
|
|
||||||
try {
|
|
||||||
deleteApplication(id);
|
|
||||||
} catch (WebApplicationException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
applications.put(id, application);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PUT
|
|
||||||
@Path("realms/{id}")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public void save(@PathParam("id") String id, Realm realm) {
|
|
||||||
try {
|
|
||||||
deleteRealm(id);
|
|
||||||
} catch (WebApplicationException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
realms.put(id, realm);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("realms/{realm}/users/{id}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public User getUser(@PathParam("realm") String realm, @PathParam("id") String id) {
|
|
||||||
for (User u : getUsers(realm)) {
|
|
||||||
if (u.getUserId().equals(id)) {
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new WebApplicationException(Status.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("realms/{realm}/users")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public List<User> getUsers(@PathParam("realm") String realm) {
|
|
||||||
List<User> l = users.get(realm);
|
|
||||||
if (l == null) {
|
|
||||||
l = new LinkedList<User>();
|
|
||||||
users.put(realm, l);
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PUT
|
|
||||||
@Path("realms/{realm}/users/{id}")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public void save(@PathParam("realm") String realm, @PathParam("id") String id, User user) {
|
|
||||||
try {
|
|
||||||
deleteUser(realm, id);
|
|
||||||
} catch (WebApplicationException e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
getUsers(realm).add(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DELETE
|
|
||||||
@Path("realms/{realm}/users/{id}")
|
|
||||||
public void deleteUser(@PathParam("realm") String realm, @PathParam("id") String id) {
|
|
||||||
getUsers(realm).remove(getUser(realm, id));
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
@Path("roles/{realm}/{role}")
|
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
|
||||||
public List<User> getRoleMapping(@PathParam("realm") String realm, @PathParam("role") String role) {
|
|
||||||
List<String> ids = getRoleMapping(new Id(realm, role));
|
|
||||||
|
|
||||||
List<User> users = new LinkedList<User>();
|
|
||||||
List<User> realmUsers = getUsers(realm);
|
|
||||||
for (String id : ids) {
|
|
||||||
for (User u : realmUsers) {
|
|
||||||
if (u.getUserId().equals(id)) {
|
|
||||||
users.add(u);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getRoleMapping(Id id) {
|
|
||||||
List<String> l = roles.get(id);
|
|
||||||
if (l == null) {
|
|
||||||
l = new LinkedList<String>();
|
|
||||||
roles.put(id, l);
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PUT
|
|
||||||
@Path("roles/{realm}/{role}/{user}")
|
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
|
||||||
public void addRoleMapping(@PathParam("realm") String realm, @PathParam("role") String role,
|
|
||||||
@PathParam("user") String user, User u) {
|
|
||||||
getRoleMapping(new Id(realm, role)).add(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DELETE
|
|
||||||
@Path("roles/{realm}/{role}/{user}")
|
|
||||||
public void deleteRoleMapping(@PathParam("realm") String realm, @PathParam("role") String role,
|
|
||||||
@PathParam("user") String user) {
|
|
||||||
Iterator<String> itr = getRoleMapping(new Id(realm, role)).iterator();
|
|
||||||
while (itr.hasNext()) {
|
|
||||||
if (itr.next().equals(user)) {
|
|
||||||
itr.remove();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new WebApplicationException(Status.NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,102 +0,0 @@
|
||||||
/*
|
|
||||||
* JBoss, Home of Professional Open Source.
|
|
||||||
* Copyright 2012, Red Hat, Inc., and individual contributors
|
|
||||||
* as indicated by the @author tags. See the copyright.txt file in the
|
|
||||||
* distribution for a full listing of individual contributors.
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this software; if not, write to the Free
|
|
||||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
||||||
*/
|
|
||||||
package org.keycloak.ui.example;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
@XmlRootElement
|
|
||||||
public class Application {
|
|
||||||
|
|
||||||
private String[] callbackUrl;
|
|
||||||
|
|
||||||
private boolean enabled;
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
private String[] initialRoles;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private String realm;
|
|
||||||
|
|
||||||
private String[] roles;
|
|
||||||
|
|
||||||
public String[] getCallbackUrl() {
|
|
||||||
return callbackUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getInitialRoles() {
|
|
||||||
return initialRoles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRealm() {
|
|
||||||
return realm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getRoles() {
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCallbackUrl(String[] callbackUrl) {
|
|
||||||
this.callbackUrl = callbackUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitialRoles(String[] initialRoles) {
|
|
||||||
this.initialRoles = initialRoles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRealm(String realm) {
|
|
||||||
this.realm = realm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRoles(String[] roles) {
|
|
||||||
this.roles = roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package org.keycloak.ui.example;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
@XmlRootElement
|
|
||||||
public class Attribute implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private String value;
|
|
||||||
|
|
||||||
public Attribute() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Attribute(String name, String value) {
|
|
||||||
this.name = name;
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package org.keycloak.ui.example;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class Id {
|
|
||||||
|
|
||||||
private String[] id;
|
|
||||||
|
|
||||||
public Id(String... id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId(int i) {
|
|
||||||
return id[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + Arrays.hashCode(id);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
|
||||||
return false;
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
return false;
|
|
||||||
Id other = (Id) obj;
|
|
||||||
if (!Arrays.equals(id, other.id))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* JBoss, Home of Professional Open Source.
|
|
||||||
* Copyright 2012, Red Hat, Inc., and individual contributors
|
|
||||||
* as indicated by the @author tags. See the copyright.txt file in the
|
|
||||||
* distribution for a full listing of individual contributors.
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this software; if not, write to the Free
|
|
||||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
||||||
*/
|
|
||||||
package org.keycloak.ui.example;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
@XmlRootElement
|
|
||||||
public class IdentityProviderConfig {
|
|
||||||
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String key;
|
|
||||||
|
|
||||||
private String providerId;
|
|
||||||
|
|
||||||
private String secret;
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProviderId() {
|
|
||||||
return providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSecret() {
|
|
||||||
return secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKey(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProviderId(String providerId) {
|
|
||||||
this.providerId = providerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSecret(String secret) {
|
|
||||||
this.secret = secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* JBoss, Home of Professional Open Source.
|
|
||||||
* Copyright 2012, Red Hat, Inc., and individual contributors
|
|
||||||
* as indicated by the @author tags. See the copyright.txt file in the
|
|
||||||
* distribution for a full listing of individual contributors.
|
|
||||||
*
|
|
||||||
* This is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU Lesser General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2.1 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this software; if not, write to the Free
|
|
||||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
||||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
|
||||||
*/
|
|
||||||
package org.keycloak.ui.example;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class Realm {
|
|
||||||
|
|
||||||
private boolean enabled;
|
|
||||||
|
|
||||||
private String[] initialRoles;
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
private String[] roles;
|
|
||||||
|
|
||||||
private boolean social;
|
|
||||||
|
|
||||||
private long tokenExpiration;
|
|
||||||
|
|
||||||
private TimeUnit tokenExpirationUnit;
|
|
||||||
|
|
||||||
private boolean userRegistration;
|
|
||||||
|
|
||||||
public String[] getInitialRoles() {
|
|
||||||
return initialRoles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getRoles() {
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTokenExpiration() {
|
|
||||||
return tokenExpiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeUnit getTokenExpirationUnit() {
|
|
||||||
return tokenExpirationUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSocial() {
|
|
||||||
return social;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUserRegistration() {
|
|
||||||
return userRegistration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEnabled(boolean enabled) {
|
|
||||||
this.enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitialRoles(String[] initialRoles) {
|
|
||||||
this.initialRoles = initialRoles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRoles(String[] roles) {
|
|
||||||
this.roles = roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSocial(boolean social) {
|
|
||||||
this.social = social;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTokenExpiration(long tokenExpiration) {
|
|
||||||
this.tokenExpiration = tokenExpiration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTokenExpirationUnit(TimeUnit tokenExpirationUnit) {
|
|
||||||
this.tokenExpirationUnit = tokenExpirationUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserRegistration(boolean userRegistration) {
|
|
||||||
this.userRegistration = userRegistration;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* JBoss, Home of Professional Open Source
|
|
||||||
* Copyright 2012, Red Hat, Inc., and individual contributors
|
|
||||||
* by the @authors tag. See the copyright.txt in the distribution for a
|
|
||||||
* full listing of individual contributors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.keycloak.ui.example;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
@XmlRootElement
|
|
||||||
public class User implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private List<Attribute> attributes;
|
|
||||||
private String email;
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
private String userId;
|
|
||||||
private String password;
|
|
||||||
private String[] roles;
|
|
||||||
|
|
||||||
public String[] getRoles() {
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRoles(String[] roles) {
|
|
||||||
this.roles = roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPassword() {
|
|
||||||
return password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPassword(String password) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Attribute> getAttributes() {
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEmail() {
|
|
||||||
return email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFirstName() {
|
|
||||||
return firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLastName() {
|
|
||||||
return lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserId() {
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAttributes(List<Attribute> attributes) {
|
|
||||||
this.attributes = attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEmail(String email) {
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstName(String firstName) {
|
|
||||||
this.firstName = firstName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastName(String lastName) {
|
|
||||||
this.lastName = lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserId(String userId) {
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,314 +0,0 @@
|
||||||
/* General styles */
|
|
||||||
|
|
||||||
@media (min-width: 1200px) {
|
|
||||||
|
|
||||||
#actions-bg {width: 1150px;}
|
|
||||||
|
|
||||||
#container-right-bg {
|
|
||||||
margin-left: 300px;
|
|
||||||
width: 900px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.span9 {
|
|
||||||
width: 840px;
|
|
||||||
padding-left: 30px;
|
|
||||||
padding-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.initial {margin-left: 160px;}
|
|
||||||
|
|
||||||
.form-mobile-redirect .header-mobile-redirect .control-group,
|
|
||||||
.form-mobile-redirect .header-mobile-redirect .control-group:last-child {
|
|
||||||
width: 300px;
|
|
||||||
margin-left: 60px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-mobile-redirect input, .header-mobile-redirect select {width: 175px;}
|
|
||||||
|
|
||||||
tbody.sortable tr td:nth-child(1) {width: 150px;}
|
|
||||||
tbody.sortable tr td:nth-child(2) {width: 420px;}
|
|
||||||
tbody.sortable tr td:nth-child(3v) {width: 130px;}
|
|
||||||
|
|
||||||
#mappings .input-medium {width: 180px;}
|
|
||||||
|
|
||||||
footer {width: 1170px;}
|
|
||||||
|
|
||||||
footer p {margin-left: 300px;}
|
|
||||||
|
|
||||||
footer > ul {margin-right: 25px;}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1025px) {
|
|
||||||
|
|
||||||
td.actions > a,
|
|
||||||
td.actions > button,
|
|
||||||
td.actions > div {visibility: hidden}
|
|
||||||
|
|
||||||
tr:hover > td.actions > a,
|
|
||||||
tr:hover > td.actions > button,
|
|
||||||
tr:hover > td.actions > div {visibility: visible;}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) and (max-width: 979px) {
|
|
||||||
|
|
||||||
body {padding-top: 0;}
|
|
||||||
|
|
||||||
/* Topbar */
|
|
||||||
|
|
||||||
.navbar-fixed-top {
|
|
||||||
margin-bottom: 2px;
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-fixed-top .navbar-inner {padding: 0;}
|
|
||||||
|
|
||||||
.navbar .container {width: 724px;}
|
|
||||||
|
|
||||||
.navbar .brand {margin-left: -20px;}
|
|
||||||
|
|
||||||
.nav-collapse {
|
|
||||||
height: auto;
|
|
||||||
overflow: visible;
|
|
||||||
clear: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-collapse .nav {margin-bottom: 0;}
|
|
||||||
|
|
||||||
.navbar .nav-collapse .nav.pull-right {float: right;}
|
|
||||||
|
|
||||||
.nav-collapse .nav > li {float: left;}
|
|
||||||
|
|
||||||
.nav-collapse .nav > li > a {
|
|
||||||
font-weight: normal;
|
|
||||||
padding: 9px 10px 11px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Topbar dropdown */
|
|
||||||
|
|
||||||
.navbar .dropdown-menu {display: none;}
|
|
||||||
|
|
||||||
.open .dropdown-menu,
|
|
||||||
.open .dropdown-menu:before,
|
|
||||||
.open .dropdown-menu:after {display: block;}
|
|
||||||
|
|
||||||
.open .dropdown-menu {
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
border-radius: 5px 5px 5px 5px;
|
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
margin: 1px 0 0;
|
|
||||||
padding: 4px 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-collapse .dropdown-menu a {
|
|
||||||
color: #333333;
|
|
||||||
line-height: 18px;
|
|
||||||
padding: 3px 15px;
|
|
||||||
border-radius: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-collapse .dropdown-menu li > a:hover,
|
|
||||||
.nav-collapse .dropdown-menu .active > a,
|
|
||||||
.nav-collapse .dropdown-menu .active > a:hover {
|
|
||||||
background-color: #0088CC;
|
|
||||||
color: #FFFFFF;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Aside */
|
|
||||||
|
|
||||||
.nav-list a#add-page {top: 15px;}
|
|
||||||
|
|
||||||
#actions-bg {width: 730px;}
|
|
||||||
|
|
||||||
/* Content */
|
|
||||||
|
|
||||||
.form-horizontal .control-label {width: 125px;}
|
|
||||||
|
|
||||||
.form-horizontal .controls {margin-left: 140px;}
|
|
||||||
|
|
||||||
#container-right-bg {
|
|
||||||
margin-left: 186px;
|
|
||||||
width: 558px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.span9 {
|
|
||||||
width: 518px;
|
|
||||||
padding-left: 20px;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.initial {margin-left: 0;}
|
|
||||||
|
|
||||||
.header-mobile-redirect .control-group label {
|
|
||||||
width: 100px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-mobile-redirect .header-mobile-redirect .control-group {width: 300px;}
|
|
||||||
|
|
||||||
.form-mobile-redirect .header-mobile-redirect .control-group:last-child {
|
|
||||||
margin-left: 87px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mappings .input-medium {width: 85px;}
|
|
||||||
|
|
||||||
#space-group .top-actions .pull-right {
|
|
||||||
float: none;
|
|
||||||
clear: both;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.window-tree {width: 356px;}
|
|
||||||
|
|
||||||
/* Footer */
|
|
||||||
|
|
||||||
footer {
|
|
||||||
width: 724px;
|
|
||||||
height: 50px;
|
|
||||||
margin-top: -50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer p {
|
|
||||||
margin-left: 186px;
|
|
||||||
float: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer > ul {
|
|
||||||
margin-left: 173px;
|
|
||||||
float: none;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-fixed-top, .navbar-fixed-bottom {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Topbar */
|
|
||||||
|
|
||||||
.navbar-fixed-top {
|
|
||||||
position: absolute;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-fixed-top .navbar-inner {padding: 0;}
|
|
||||||
|
|
||||||
.nav-collapse {
|
|
||||||
height: auto;
|
|
||||||
overflow: visible;
|
|
||||||
clear: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-collapse .nav {margin-bottom: 0;}
|
|
||||||
|
|
||||||
.navbar .nav-collapse .nav.pull-right {float: right;}
|
|
||||||
|
|
||||||
.navbar #settings {display: none;}
|
|
||||||
|
|
||||||
.nav-collapse .nav > li {float: left;}
|
|
||||||
|
|
||||||
.nav-collapse .nav > li > a {
|
|
||||||
font-weight: normal;
|
|
||||||
padding: 9px 10px 11px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Topbar dropdown */
|
|
||||||
|
|
||||||
.navbar .dropdown-menu {display: none;}
|
|
||||||
|
|
||||||
.open .dropdown-menu,
|
|
||||||
.open .dropdown-menu:before,
|
|
||||||
.open .dropdown-menu:after {display: block;}
|
|
||||||
|
|
||||||
.open .dropdown-menu {
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
border-radius: 5px 5px 5px 5px;
|
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
margin: 1px 0 0;
|
|
||||||
padding: 4px 0;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-collapse .dropdown-menu a {
|
|
||||||
color: #333333;
|
|
||||||
line-height: 18px;
|
|
||||||
padding: 3px 15px;
|
|
||||||
border-radius: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-collapse .dropdown-menu li > a:hover,
|
|
||||||
.nav-collapse .dropdown-menu .active > a,
|
|
||||||
.nav-collapse .dropdown-menu .active > a:hover {
|
|
||||||
background-color: #0088CC;
|
|
||||||
color: #FFFFFF;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* */
|
|
||||||
|
|
||||||
#wrapper {margin-top: 40px;}
|
|
||||||
|
|
||||||
aside.span3,
|
|
||||||
#actions-bg,
|
|
||||||
#container-right-bg {display: none;}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
padding-left: 20px;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container-right {
|
|
||||||
box-shadow: none;
|
|
||||||
background: none;
|
|
||||||
padding-bottom: 74px;
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.span9 {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-large,
|
|
||||||
.input-xlarge,
|
|
||||||
.input-xxlarge,
|
|
||||||
input[class*="span"],
|
|
||||||
select[class*="span"],
|
|
||||||
textarea[class*="span"],
|
|
||||||
.uneditable-input {width: 80%;}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer > ul,
|
|
||||||
footer >p {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer ul li:first-child {
|
|
||||||
padding-left: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
.margin-top {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#httpProviderError {
|
|
||||||
position: fixed;
|
|
||||||
left: 20px;
|
|
||||||
bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#loading {
|
|
||||||
color: #868686;
|
|
||||||
font-size: 14px;
|
|
||||||
position: fixed;
|
|
||||||
left: 0px;
|
|
||||||
bottom: 5px;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 999 B |
Before Width: | Height: | Size: 935 B |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 80 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 4.4 KiB |
|
@ -1,50 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en" data-ng-app="keycloak">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Keycloak</title>
|
|
||||||
|
|
||||||
<link href="lib/bootstrap/css/bootstrap.css" rel="stylesheet">
|
|
||||||
<link href="lib/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
|
|
||||||
<link href="css/admin.css" rel="stylesheet">
|
|
||||||
<link href="css/admin-responsive.css" rel="stylesheet">
|
|
||||||
|
|
||||||
<link href="css/styles.css" rel="stylesheet">
|
|
||||||
|
|
||||||
<script src="lib/jquery/jquery-1.10.2.js"></script>
|
|
||||||
|
|
||||||
<script src="lib/angular/angular.js"></script>
|
|
||||||
<script src="lib/angular/angular-resource.js"></script>
|
|
||||||
<script src="lib/angular/ui-bootstrap-tpls-0.4.0.js"></script>
|
|
||||||
|
|
||||||
<script src="js/app.js"></script>
|
|
||||||
<script src="js/controllers.js"></script>
|
|
||||||
<script src="js/loaders.js"></script>
|
|
||||||
<script src="js/services.js"></script>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body data-ng-controller="GlobalCtrl">
|
|
||||||
|
|
||||||
<div class="alert-container" data-ng-show="notification" data-ng-click="notification = null">
|
|
||||||
<div class="alert alert-{{notification.type}}">{{notification.message}}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="wrap">
|
|
||||||
<div data-ng-include data-src="'partials/menu.html'"></div>
|
|
||||||
|
|
||||||
<div data-ng-view id="view" data-ng-hide="httpProviderError"></div>
|
|
||||||
|
|
||||||
<div id="httpProviderError" data-ng-show="httpProviderError">
|
|
||||||
<button class="btn btn-danger" data-ng-click="httpProviderError=null">
|
|
||||||
<strong>Error</strong> {{httpProviderError}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="loading">
|
|
||||||
<i class="icon-spinner icon-spin"></i> Loading...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,290 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'keycloak.controllers', 'ui.bootstrap' ]);
|
|
||||||
var resourceRequests = 0;
|
|
||||||
|
|
||||||
module.config([ '$routeProvider', function($routeProvider) {
|
|
||||||
|
|
||||||
$routeProvider.when('/create/application', {
|
|
||||||
templateUrl : 'partials/application-detail.html',
|
|
||||||
resolve : {
|
|
||||||
application : function(ApplicationLoader) {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
realms : function(RealmListLoader) {
|
|
||||||
return RealmListLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'ApplicationDetailCtrl'
|
|
||||||
}).when('/applications/:application', {
|
|
||||||
templateUrl : 'partials/application-detail.html',
|
|
||||||
resolve : {
|
|
||||||
application : function(ApplicationLoader) {
|
|
||||||
return ApplicationLoader();
|
|
||||||
},
|
|
||||||
realms : function(RealmListLoader) {
|
|
||||||
return RealmListLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'ApplicationDetailCtrl'
|
|
||||||
}).when('/applications', {
|
|
||||||
templateUrl : 'partials/application-list.html',
|
|
||||||
resolve : {
|
|
||||||
applications : function(ApplicationListLoader) {
|
|
||||||
return ApplicationListLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'ApplicationListCtrl'
|
|
||||||
})
|
|
||||||
|
|
||||||
.when('/create/realm', {
|
|
||||||
templateUrl : 'partials/realm-detail.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(RealmLoader) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'RealmDetailCtrl'
|
|
||||||
}).when('/realms/:realm', {
|
|
||||||
templateUrl : 'partials/realm-detail.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(RealmLoader) {
|
|
||||||
return RealmLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'RealmDetailCtrl'
|
|
||||||
}).when('/realms', {
|
|
||||||
templateUrl : 'partials/realm-list.html',
|
|
||||||
controller : 'RealmListCtrl'
|
|
||||||
})
|
|
||||||
|
|
||||||
.when('/create/user/:realm', {
|
|
||||||
templateUrl : 'partials/user-detail.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(RealmLoader) {
|
|
||||||
return RealmLoader();
|
|
||||||
},
|
|
||||||
user : function() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'UserDetailCtrl'
|
|
||||||
}).when('/realms/:realm/users/:user', {
|
|
||||||
templateUrl : 'partials/user-detail.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(RealmLoader) {
|
|
||||||
return RealmLoader();
|
|
||||||
},
|
|
||||||
user : function(UserLoader) {
|
|
||||||
return UserLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'UserDetailCtrl'
|
|
||||||
}).when('/realms/:realm/users', {
|
|
||||||
templateUrl : 'partials/user-list.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(RealmLoader) {
|
|
||||||
return RealmLoader();
|
|
||||||
},
|
|
||||||
users : function(UserListLoader) {
|
|
||||||
return UserListLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'UserListCtrl'
|
|
||||||
})
|
|
||||||
|
|
||||||
.when('/realms/:realm/roles', {
|
|
||||||
templateUrl : 'partials/role-mapping.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(RealmLoader) {
|
|
||||||
return RealmLoader();
|
|
||||||
},
|
|
||||||
application : function() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
users : function() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
role : function() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'RoleMappingCtrl'
|
|
||||||
}).when('/realms/:realm/roles/:role', {
|
|
||||||
templateUrl : 'partials/role-mapping.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(RealmLoader) {
|
|
||||||
return RealmLoader();
|
|
||||||
},
|
|
||||||
application : function() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
role : function($route) {
|
|
||||||
return $route.current.params.role;
|
|
||||||
},
|
|
||||||
users : function(RoleMappingLoader) {
|
|
||||||
return RoleMappingLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'RoleMappingCtrl'
|
|
||||||
})
|
|
||||||
|
|
||||||
.when('/applications/:application/roles', {
|
|
||||||
templateUrl : 'partials/role-mapping.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(ApplicationLoader) {
|
|
||||||
return ApplicationLoader();
|
|
||||||
},
|
|
||||||
users : function() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
role : function() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'RoleMappingCtrl'
|
|
||||||
}).when('/applications/:application/roles/:role', {
|
|
||||||
templateUrl : 'partials/role-mapping.html',
|
|
||||||
resolve : {
|
|
||||||
realm : function(ApplicationLoader) {
|
|
||||||
return ApplicationLoader();
|
|
||||||
},
|
|
||||||
role : function($route) {
|
|
||||||
return $route.current.params.role;
|
|
||||||
},
|
|
||||||
users : function(RoleMappingLoader) {
|
|
||||||
return RoleMappingLoader();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
controller : 'RoleMappingCtrl'
|
|
||||||
})
|
|
||||||
|
|
||||||
.otherwise({
|
|
||||||
templateUrl : 'partials/home.html'
|
|
||||||
});
|
|
||||||
} ]);
|
|
||||||
|
|
||||||
module.config(function($httpProvider) {
|
|
||||||
$httpProvider.responseInterceptors.push('errorInterceptor');
|
|
||||||
|
|
||||||
var spinnerFunction = function(data, headersGetter) {
|
|
||||||
if (resourceRequests == 0) {
|
|
||||||
$('#loading').show();
|
|
||||||
}
|
|
||||||
resourceRequests++;
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
$httpProvider.defaults.transformRequest.push(spinnerFunction);
|
|
||||||
|
|
||||||
$httpProvider.responseInterceptors.push('spinnerInterceptor');
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('errorInterceptor', function($q, $window, $rootScope, $location) {
|
|
||||||
return function(promise) {
|
|
||||||
return promise.then(function(response) {
|
|
||||||
$rootScope.httpProviderError = null;
|
|
||||||
return response;
|
|
||||||
}, function(response) {
|
|
||||||
$rootScope.httpProviderError = response.status;
|
|
||||||
return $q.reject(response);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('spinnerInterceptor', function($q, $window, $rootScope, $location) {
|
|
||||||
return function(promise) {
|
|
||||||
return promise.then(function(response) {
|
|
||||||
resourceRequests--;
|
|
||||||
if (resourceRequests == 0) {
|
|
||||||
$('#loading').hide();
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}, function(response) {
|
|
||||||
resourceRequests--;
|
|
||||||
if (resourceRequests == 0) {
|
|
||||||
$('#loading').hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $q.reject(response);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
module.directive('kcInput', function() {
|
|
||||||
var d = {
|
|
||||||
scope : true,
|
|
||||||
replace : false,
|
|
||||||
link : function(scope, element, attrs) {
|
|
||||||
var form = element.closest('form');
|
|
||||||
var label = element.children('label');
|
|
||||||
var input = element.children('input');
|
|
||||||
|
|
||||||
var id = form.attr('name') + '.' + input.attr('name');
|
|
||||||
|
|
||||||
element.attr('class', 'control-group');
|
|
||||||
|
|
||||||
label.attr('class', 'control-label');
|
|
||||||
label.attr('for', id);
|
|
||||||
|
|
||||||
input.wrap('<div class="controls"/>');
|
|
||||||
input.attr('id', id);
|
|
||||||
|
|
||||||
if (!input.attr('placeHolder')) {
|
|
||||||
input.attr('placeHolder', label.text());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input.attr('required')) {
|
|
||||||
label.append(' <span class="required">*</span>');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return d;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.directive('kcEnter', function() {
|
|
||||||
return function(scope, element, attrs) {
|
|
||||||
element.bind("keydown keypress", function(event) {
|
|
||||||
if (event.which === 13) {
|
|
||||||
scope.$apply(function() {
|
|
||||||
scope.$eval(attrs.kcEnter);
|
|
||||||
});
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
module.filter('remove', function() {
|
|
||||||
return function(input, remove, attribute) {
|
|
||||||
if (!input || !remove) {
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
var out = [];
|
|
||||||
for ( var i = 0; i < input.length; i++) {
|
|
||||||
var e = input[i];
|
|
||||||
|
|
||||||
for (var j = 0; j < remove.length; j++) {
|
|
||||||
if (attribute) {
|
|
||||||
if (remove[j][attribute] == e[attribute]) {
|
|
||||||
e = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (remove[j] == e) {
|
|
||||||
e = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e != null) {
|
|
||||||
out.push(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
};
|
|
||||||
});
|
|
|
@ -1,348 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('keycloak.controllers', [ 'keycloak.services' ]);
|
|
||||||
|
|
||||||
module.controller('GlobalCtrl', function($scope, Auth, $location, Notifications) {
|
|
||||||
$scope.addMessage = function() {
|
|
||||||
Notifications.success("test");
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.auth = Auth;
|
|
||||||
|
|
||||||
$scope.$watch(function() {
|
|
||||||
return $location.path();
|
|
||||||
}, function() {
|
|
||||||
$scope.path = $location.path().substring(1).split("/");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.controller('ApplicationListCtrl', function($scope, Application) {
|
|
||||||
$scope.applications = Application.query();
|
|
||||||
});
|
|
||||||
|
|
||||||
module.controller('ApplicationDetailCtrl', function($scope, application, Application, realms, $location, $window, Dialog,
|
|
||||||
Notifications) {
|
|
||||||
$scope.application = angular.copy(application);
|
|
||||||
$scope.realms = realms;
|
|
||||||
|
|
||||||
$scope.create = !application.id;
|
|
||||||
$scope.changed = $scope.create;
|
|
||||||
|
|
||||||
$scope.$watch('application', function() {
|
|
||||||
if (!angular.equals($scope.application, application)) {
|
|
||||||
$scope.changed = true;
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
$scope.addRole = function() {
|
|
||||||
if ($scope.newRole) {
|
|
||||||
if ($scope.application.roles) {
|
|
||||||
for ( var i = 0; i < $scope.application.roles.length; i++) {
|
|
||||||
if ($scope.application.roles[i] == $scope.newRole) {
|
|
||||||
Notifications.warn("Role already exists");
|
|
||||||
$scope.newRole = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$scope.application.roles) {
|
|
||||||
$scope.application.roles = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.application.roles.push($scope.newRole);
|
|
||||||
$scope.newRole = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.removeRole = function(role) {
|
|
||||||
Dialog.confirmDelete(role, 'role', function() {
|
|
||||||
var i = $scope.application.roles.indexOf(role);
|
|
||||||
if (i > -1) {
|
|
||||||
$scope.application.roles.splice(i, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($scope.application.initialRoles) {
|
|
||||||
$scope.removeInitialRole(role);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.addInitialRole = function() {
|
|
||||||
if ($scope.newInitialRole) {
|
|
||||||
if (!$scope.application.initialRoles) {
|
|
||||||
$scope.application.initialRoles = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.application.initialRoles.push($scope.newInitialRole);
|
|
||||||
$scope.newInitialRole = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.removeInitialRole = function(role) {
|
|
||||||
var i = $scope.application.initialRoles.indexOf(role);
|
|
||||||
if (i > -1) {
|
|
||||||
$scope.application.initialRoles.splice(i, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.save = function() {
|
|
||||||
if ($scope.applicationForm.$valid) {
|
|
||||||
if ($scope.create) {
|
|
||||||
Application.save($scope.application, function(data, headers) {
|
|
||||||
var l = headers().location;
|
|
||||||
var id = l.substring(l.lastIndexOf("/") + 1);
|
|
||||||
$location.url("/applications/" + id);
|
|
||||||
Notifications.success("Created application");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Application.update($scope.application, function() {
|
|
||||||
$scope.changed = false;
|
|
||||||
application = angular.copy($scope.application);
|
|
||||||
Notifications.success("Saved changes to the application");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$scope.applicationForm.showErrors = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.reset = function() {
|
|
||||||
$scope.application = angular.copy(application);
|
|
||||||
$scope.changed = false;
|
|
||||||
$scope.applicationForm.showErrors = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.cancel = function() {
|
|
||||||
$location.url("/applications");
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.remove = function() {
|
|
||||||
Dialog.confirmDelete($scope.application.name, 'application', function() {
|
|
||||||
$scope.application.$remove(function() {
|
|
||||||
$location.url("/applications");
|
|
||||||
Notifications.success("Deleted application");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
module.controller('RealmListCtrl', function($scope, Realm) {
|
|
||||||
$scope.realms = Realm.query();
|
|
||||||
});
|
|
||||||
|
|
||||||
module.controller('RealmDetailCtrl', function($scope, Realm, realm, $location, Dialog, Notifications) {
|
|
||||||
$scope.realm = angular.copy(realm);
|
|
||||||
$scope.create = !realm.name;
|
|
||||||
|
|
||||||
$scope.changed = $scope.create;
|
|
||||||
|
|
||||||
$scope.$watch('realm', function() {
|
|
||||||
if (!angular.equals($scope.realm, realm)) {
|
|
||||||
$scope.changed = true;
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
$scope.addRole = function() {
|
|
||||||
if ($scope.newRole) {
|
|
||||||
if ($scope.realm.roles) {
|
|
||||||
for ( var i = 0; i < $scope.realm.roles.length; i++) {
|
|
||||||
if ($scope.realm.roles[i] == $scope.newRole) {
|
|
||||||
Notifications.warn("Role already exists");
|
|
||||||
$scope.newRole = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$scope.realm.roles) {
|
|
||||||
$scope.realm.roles = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.realm.roles.push($scope.newRole);
|
|
||||||
$scope.newRole = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.removeRole = function(role) {
|
|
||||||
Dialog.confirmDelete(role, 'role', function() {
|
|
||||||
var i = $scope.realm.roles.indexOf(role);
|
|
||||||
if (i > -1) {
|
|
||||||
$scope.realm.roles.splice(i, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($scope.realm.initialRoles) {
|
|
||||||
$scope.removeInitialRole(role);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.addInitialRole = function() {
|
|
||||||
if ($scope.newInitialRole) {
|
|
||||||
if (!$scope.realm.initialRoles) {
|
|
||||||
$scope.realm.initialRoles = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.realm.initialRoles.push($scope.newInitialRole);
|
|
||||||
$scope.newInitialRole = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.removeInitialRole = function(role) {
|
|
||||||
var i = $scope.realm.initialRoles.indexOf(role);
|
|
||||||
if (i > -1) {
|
|
||||||
$scope.realm.initialRoles.splice(i, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.save = function() {
|
|
||||||
if ($scope.realmForm.$valid) {
|
|
||||||
if ($scope.create) {
|
|
||||||
Realm.save($scope.realm, function(data, headers) {
|
|
||||||
var l = headers().location;
|
|
||||||
var id = l.substring(l.lastIndexOf("/") + 1);
|
|
||||||
$location.url("/realms/" + id);
|
|
||||||
Notifications.success("Created realm");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Realm.update($scope.realm, function() {
|
|
||||||
$scope.changed = false;
|
|
||||||
realm = angular.copy($scope.realm);
|
|
||||||
Notifications.success("Saved changes to realm");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$scope.realmForm.showErrors = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.reset = function() {
|
|
||||||
$scope.realm = angular.copy(realm);
|
|
||||||
$scope.changed = false;
|
|
||||||
$scope.realmForm.showErrors = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.cancel = function() {
|
|
||||||
$location.url("/realms");
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.remove = function() {
|
|
||||||
Dialog.confirmDelete($scope.realm.name, 'realm', function() {
|
|
||||||
Realm.remove($scope.realm, function() {
|
|
||||||
$location.url("/realms");
|
|
||||||
Notifications.success("Deleted realm");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
module.controller('UserListCtrl', function($scope, realm, users) {
|
|
||||||
$scope.realm = realm;
|
|
||||||
$scope.users = users;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.controller('UserDetailCtrl', function($scope, realm, user, User, $location, Dialog, Notifications) {
|
|
||||||
$scope.realm = realm;
|
|
||||||
$scope.user = angular.copy(user);
|
|
||||||
$scope.create = !user.userId;
|
|
||||||
|
|
||||||
$scope.changed = $scope.create;
|
|
||||||
|
|
||||||
$scope.$watch('user', function() {
|
|
||||||
if (!angular.equals($scope.user, user)) {
|
|
||||||
$scope.changed = true;
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
$scope.save = function() {
|
|
||||||
if ($scope.userForm.$valid) {
|
|
||||||
User.save({
|
|
||||||
realm : realm.id,
|
|
||||||
}, $scope.user, function() {
|
|
||||||
$scope.changed = false;
|
|
||||||
user = angular.copy($scope.user);
|
|
||||||
|
|
||||||
if ($scope.create) {
|
|
||||||
$location.url("/realms/" + realm.id + "/users/" + $scope.user.userId);
|
|
||||||
Notifications.success("Created user");
|
|
||||||
} else {
|
|
||||||
Notifications.success("Saved changes to user");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$scope.userForm.showErrors = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.reset = function() {
|
|
||||||
$scope.user = angular.copy(user);
|
|
||||||
$scope.changed = false;
|
|
||||||
$scope.userForm.showErrors = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.cancel = function() {
|
|
||||||
$location.url("/realms/" + realm.id + "/users");
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.remove = function() {
|
|
||||||
Dialog.confirmDelete($scope.user.userId, 'user', function() {
|
|
||||||
$scope.user.$remove({
|
|
||||||
realm : realm.id,
|
|
||||||
userId : $scope.user.userId
|
|
||||||
}, function() {
|
|
||||||
$location.url("/realms/" + realm.id + "/users");
|
|
||||||
Notifications.success("Deleted user");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
module.controller('RoleMappingCtrl', function($scope, realm, User, users, role, RoleMapping, Notifications) {
|
|
||||||
$scope.realm = realm;
|
|
||||||
$scope.realmId = realm.realm || realm.id;
|
|
||||||
$scope.allUsers = User.query({ realm : $scope.realmId });
|
|
||||||
$scope.users = users;
|
|
||||||
$scope.role = role;
|
|
||||||
|
|
||||||
$scope.addUser = function() {
|
|
||||||
var user = $scope.newUser;
|
|
||||||
$scope.newUser = null;
|
|
||||||
|
|
||||||
for ( var i = 0; i < $scope.allUsers.length; i++) {
|
|
||||||
if ($scope.allUsers[i].userId == user) {
|
|
||||||
user = $scope.allUsers[i];
|
|
||||||
RoleMapping.save({
|
|
||||||
realm : $scope.realmId,
|
|
||||||
role : role
|
|
||||||
}, user, function() {
|
|
||||||
$scope.users = RoleMapping.query({
|
|
||||||
realm : $scope.realmId,
|
|
||||||
role : role
|
|
||||||
});
|
|
||||||
Notifications.success("Added role mapping for user");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.removeUser = function(userId) {
|
|
||||||
for (var i = 0; i < $scope.users.length; i++) {
|
|
||||||
var user = $scope.users[i];
|
|
||||||
if ($scope.users[i].userId == userId) {
|
|
||||||
RoleMapping.delete({
|
|
||||||
realm : $scope.realmId,
|
|
||||||
role : role
|
|
||||||
}, user, function() {
|
|
||||||
$scope.users = RoleMapping.query({
|
|
||||||
realm : $scope.realmId,
|
|
||||||
role : role
|
|
||||||
});
|
|
||||||
|
|
||||||
Notifications.success("Removed role mapping for user");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,84 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('keycloak.loaders', [ 'keycloak.services', 'ngResource' ]);
|
|
||||||
|
|
||||||
module.factory('Loader', function($q) {
|
|
||||||
var loader = {};
|
|
||||||
loader.get = function(service, id) {
|
|
||||||
return function() {
|
|
||||||
var i = id && id();
|
|
||||||
var delay = $q.defer();
|
|
||||||
service.get(i, function(entry) {
|
|
||||||
delay.resolve(entry);
|
|
||||||
}, function() {
|
|
||||||
delay.reject('Unable to fetch ' + i);
|
|
||||||
});
|
|
||||||
return delay.promise;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
loader.query = function(service, id) {
|
|
||||||
return function() {
|
|
||||||
var i = id && id();
|
|
||||||
var delay = $q.defer();
|
|
||||||
service.query(i, function(entry) {
|
|
||||||
delay.resolve(entry);
|
|
||||||
}, function() {
|
|
||||||
delay.reject('Unable to fetch ' + i);
|
|
||||||
});
|
|
||||||
return delay.promise;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return loader;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('ApplicationListLoader', function(Loader, Application, $q) {
|
|
||||||
return Loader.query(Application);
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('ApplicationLoader', function(Loader, Application, $route, $q) {
|
|
||||||
return Loader.get(Application, function() {
|
|
||||||
return {
|
|
||||||
id : $route.current.params.application
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('RealmListLoader', function(Loader, Realm, $q) {
|
|
||||||
return Loader.query(Realm);
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('RealmLoader', function(Loader, Realm, $route, $q) {
|
|
||||||
return Loader.get(Realm, function() {
|
|
||||||
return {
|
|
||||||
id : $route.current.params.realm
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('UserListLoader', function(Loader, User, $route, $q) {
|
|
||||||
return Loader.query(User, function() {
|
|
||||||
return {
|
|
||||||
realm : $route.current.params.realm
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('UserLoader', function(Loader, User, $route, $q) {
|
|
||||||
return Loader.get(User, function() {
|
|
||||||
return {
|
|
||||||
realm : $route.current.params.realm,
|
|
||||||
userId : $route.current.params.user
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('RoleMappingLoader', function(Loader, RoleMapping, $route, $q) {
|
|
||||||
var realm = $route.current.params.realm || $route.current.params.application;
|
|
||||||
|
|
||||||
return Loader.query(RoleMapping, function() {
|
|
||||||
return {
|
|
||||||
realm : realm,
|
|
||||||
role : $route.current.params.role
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,131 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('keycloak.services', [ 'ngResource' ]);
|
|
||||||
|
|
||||||
module.service('Auth', function($resource, $http, $location, $routeParams) {
|
|
||||||
var auth = {
|
|
||||||
loggedIn : true
|
|
||||||
};
|
|
||||||
auth.user = {
|
|
||||||
userId : 'test',
|
|
||||||
displayName : 'Test User'
|
|
||||||
};
|
|
||||||
return auth;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.service('Dialog', function($dialog) {
|
|
||||||
var dialog = {};
|
|
||||||
dialog.confirmDelete = function(name, type, success) {
|
|
||||||
var title = 'Delete ' + name;
|
|
||||||
var msg = 'Are you sure you want to permanently delete this ' + type + '?';
|
|
||||||
var btns = [ {
|
|
||||||
result : 'cancel',
|
|
||||||
label : 'Cancel'
|
|
||||||
}, {
|
|
||||||
result : 'ok',
|
|
||||||
label : 'Delete this ' + type,
|
|
||||||
cssClass : 'btn-primary'
|
|
||||||
} ];
|
|
||||||
|
|
||||||
$dialog.messageBox(title, msg, btns).open().then(function(result) {
|
|
||||||
if (result == "ok") {
|
|
||||||
success();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return dialog
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('Notifications', function($rootScope, $timeout) {
|
|
||||||
var notifications = {};
|
|
||||||
|
|
||||||
var scheduled = null;
|
|
||||||
var schedulePop = function() {
|
|
||||||
if (scheduled) {
|
|
||||||
$timeout.cancel(scheduled);
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduled = $timeout(function() {
|
|
||||||
$rootScope.notification = null;
|
|
||||||
scheduled = null;
|
|
||||||
}, 3000);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!$rootScope.notifications) {
|
|
||||||
$rootScope.notifications = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
notifications.message = function(type, message) {
|
|
||||||
$rootScope.notification = {
|
|
||||||
type : type,
|
|
||||||
message : message
|
|
||||||
};
|
|
||||||
|
|
||||||
schedulePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
notifications.info = function(message) {
|
|
||||||
notifications.message("info", message);
|
|
||||||
};
|
|
||||||
|
|
||||||
notifications.success = function(message) {
|
|
||||||
notifications.message("success", message);
|
|
||||||
};
|
|
||||||
|
|
||||||
notifications.error = function(message) {
|
|
||||||
notifications.message("error", message);
|
|
||||||
};
|
|
||||||
|
|
||||||
notifications.warn = function(message) {
|
|
||||||
notifications.message("warn", message);
|
|
||||||
};
|
|
||||||
|
|
||||||
return notifications;
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('Application', function($resource) {
|
|
||||||
return $resource('/keycloak-server/ui/api/applications/:id', {
|
|
||||||
id : '@id'
|
|
||||||
}, {
|
|
||||||
update : {
|
|
||||||
method : 'PUT'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('Provider', function($resource) {
|
|
||||||
return $resource('/ejs-identity/api/admin/providers');
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('Realm', function($resource) {
|
|
||||||
return $resource('/keycloak-server/ui/api/realms/:id', {
|
|
||||||
id : '@id'
|
|
||||||
}, {
|
|
||||||
update : {
|
|
||||||
method : 'PUT'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('RoleMapping', function($resource) {
|
|
||||||
return $resource('/keycloak-server/ui/api/roles/:realm/:role/:userId', {
|
|
||||||
realm : '@realm',
|
|
||||||
role : '@role',
|
|
||||||
userId : '@userId'
|
|
||||||
}, {
|
|
||||||
save : {
|
|
||||||
method : 'PUT'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
module.factory('User', function($resource) {
|
|
||||||
return $resource('/keycloak-server/ui/api/realms/:realm/users/:userId', {
|
|
||||||
realm : '@realm',
|
|
||||||
userId : '@userId'
|
|
||||||
}, {
|
|
||||||
save : {
|
|
||||||
method : 'PUT'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,175 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.0.7
|
|
||||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window, angular, undefined) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var directive = {};
|
|
||||||
|
|
||||||
directive.dropdownToggle =
|
|
||||||
['$document', '$location', '$window',
|
|
||||||
function ($document, $location, $window) {
|
|
||||||
var openElement = null, close;
|
|
||||||
return {
|
|
||||||
restrict: 'C',
|
|
||||||
link: function(scope, element, attrs) {
|
|
||||||
scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
|
|
||||||
close && close();
|
|
||||||
});
|
|
||||||
|
|
||||||
element.parent().bind('click', function(event) {
|
|
||||||
close && close();
|
|
||||||
});
|
|
||||||
|
|
||||||
element.bind('click', function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
var iWasOpen = false;
|
|
||||||
|
|
||||||
if (openElement) {
|
|
||||||
iWasOpen = openElement === element;
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!iWasOpen){
|
|
||||||
element.parent().addClass('open');
|
|
||||||
openElement = element;
|
|
||||||
|
|
||||||
close = function (event) {
|
|
||||||
event && event.preventDefault();
|
|
||||||
event && event.stopPropagation();
|
|
||||||
$document.unbind('click', close);
|
|
||||||
element.parent().removeClass('open');
|
|
||||||
close = null;
|
|
||||||
openElement = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$document.bind('click', close);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
|
|
||||||
|
|
||||||
directive.tabbable = function() {
|
|
||||||
return {
|
|
||||||
restrict: 'C',
|
|
||||||
compile: function(element) {
|
|
||||||
var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
|
|
||||||
tabContent = angular.element('<div class="tab-content"></div>');
|
|
||||||
|
|
||||||
tabContent.append(element.contents());
|
|
||||||
element.append(navTabs).append(tabContent);
|
|
||||||
},
|
|
||||||
controller: ['$scope', '$element', function($scope, $element) {
|
|
||||||
var navTabs = $element.contents().eq(0),
|
|
||||||
ngModel = $element.controller('ngModel') || {},
|
|
||||||
tabs = [],
|
|
||||||
selectedTab;
|
|
||||||
|
|
||||||
ngModel.$render = function() {
|
|
||||||
var $viewValue = this.$viewValue;
|
|
||||||
|
|
||||||
if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
|
|
||||||
if(selectedTab) {
|
|
||||||
selectedTab.paneElement.removeClass('active');
|
|
||||||
selectedTab.tabElement.removeClass('active');
|
|
||||||
selectedTab = null;
|
|
||||||
}
|
|
||||||
if($viewValue) {
|
|
||||||
for(var i = 0, ii = tabs.length; i < ii; i++) {
|
|
||||||
if ($viewValue == tabs[i].value) {
|
|
||||||
selectedTab = tabs[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (selectedTab) {
|
|
||||||
selectedTab.paneElement.addClass('active');
|
|
||||||
selectedTab.tabElement.addClass('active');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.addPane = function(element, attr) {
|
|
||||||
var li = angular.element('<li><a href></a></li>'),
|
|
||||||
a = li.find('a'),
|
|
||||||
tab = {
|
|
||||||
paneElement: element,
|
|
||||||
paneAttrs: attr,
|
|
||||||
tabElement: li
|
|
||||||
};
|
|
||||||
|
|
||||||
tabs.push(tab);
|
|
||||||
|
|
||||||
attr.$observe('value', update)();
|
|
||||||
attr.$observe('title', function(){ update(); a.text(tab.title); })();
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
tab.title = attr.title;
|
|
||||||
tab.value = attr.value || attr.title;
|
|
||||||
if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
|
|
||||||
// we are not part of angular
|
|
||||||
ngModel.$viewValue = tab.value;
|
|
||||||
}
|
|
||||||
ngModel.$render();
|
|
||||||
}
|
|
||||||
|
|
||||||
navTabs.append(li);
|
|
||||||
li.bind('click', function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
if (ngModel.$setViewValue) {
|
|
||||||
$scope.$apply(function() {
|
|
||||||
ngModel.$setViewValue(tab.value);
|
|
||||||
ngModel.$render();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// we are not part of angular
|
|
||||||
ngModel.$viewValue = tab.value;
|
|
||||||
ngModel.$render();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return function() {
|
|
||||||
tab.tabElement.remove();
|
|
||||||
for(var i = 0, ii = tabs.length; i < ii; i++ ) {
|
|
||||||
if (tab == tabs[i]) {
|
|
||||||
tabs.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
directive.table = function() {
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
link: function(scope, element, attrs) {
|
|
||||||
element[0].className = 'table table-bordered table-striped code-table';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
directive.tabPane = function() {
|
|
||||||
return {
|
|
||||||
require: '^tabbable',
|
|
||||||
restrict: 'C',
|
|
||||||
link: function(scope, element, attrs, tabsCtrl) {
|
|
||||||
element.bind('$remove', tabsCtrl.addPane(element, attrs));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('bootstrap', []).directive(directive);
|
|
||||||
|
|
||||||
|
|
||||||
})(window, window.angular);
|
|
|
@ -1,185 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.0.7
|
|
||||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window, angular, undefined) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc overview
|
|
||||||
* @name ngCookies
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('ngCookies', ['ng']).
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name ngCookies.$cookies
|
|
||||||
* @requires $browser
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Provides read/write access to browser's cookies.
|
|
||||||
*
|
|
||||||
* Only a simple Object is exposed and by adding or removing properties to/from
|
|
||||||
* this object, new cookies are created/deleted at the end of current $eval.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
<script>
|
|
||||||
function ExampleController($cookies) {
|
|
||||||
// Retrieving a cookie
|
|
||||||
var favoriteCookie = $cookies.myFavorite;
|
|
||||||
// Setting a cookie
|
|
||||||
$cookies.myFavorite = 'oatmeal';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</doc:source>
|
|
||||||
</doc:example>
|
|
||||||
*/
|
|
||||||
factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
|
|
||||||
var cookies = {},
|
|
||||||
lastCookies = {},
|
|
||||||
lastBrowserCookies,
|
|
||||||
runEval = false,
|
|
||||||
copy = angular.copy,
|
|
||||||
isUndefined = angular.isUndefined;
|
|
||||||
|
|
||||||
//creates a poller fn that copies all cookies from the $browser to service & inits the service
|
|
||||||
$browser.addPollFn(function() {
|
|
||||||
var currentCookies = $browser.cookies();
|
|
||||||
if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
|
|
||||||
lastBrowserCookies = currentCookies;
|
|
||||||
copy(currentCookies, lastCookies);
|
|
||||||
copy(currentCookies, cookies);
|
|
||||||
if (runEval) $rootScope.$apply();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
runEval = true;
|
|
||||||
|
|
||||||
//at the end of each eval, push cookies
|
|
||||||
//TODO: this should happen before the "delayed" watches fire, because if some cookies are not
|
|
||||||
// strings or browser refuses to store some cookies, we update the model in the push fn.
|
|
||||||
$rootScope.$watch(push);
|
|
||||||
|
|
||||||
return cookies;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
|
|
||||||
*/
|
|
||||||
function push() {
|
|
||||||
var name,
|
|
||||||
value,
|
|
||||||
browserCookies,
|
|
||||||
updated;
|
|
||||||
|
|
||||||
//delete any cookies deleted in $cookies
|
|
||||||
for (name in lastCookies) {
|
|
||||||
if (isUndefined(cookies[name])) {
|
|
||||||
$browser.cookies(name, undefined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//update all cookies updated in $cookies
|
|
||||||
for(name in cookies) {
|
|
||||||
value = cookies[name];
|
|
||||||
if (!angular.isString(value)) {
|
|
||||||
if (angular.isDefined(lastCookies[name])) {
|
|
||||||
cookies[name] = lastCookies[name];
|
|
||||||
} else {
|
|
||||||
delete cookies[name];
|
|
||||||
}
|
|
||||||
} else if (value !== lastCookies[name]) {
|
|
||||||
$browser.cookies(name, value);
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//verify what was actually stored
|
|
||||||
if (updated){
|
|
||||||
updated = false;
|
|
||||||
browserCookies = $browser.cookies();
|
|
||||||
|
|
||||||
for (name in cookies) {
|
|
||||||
if (cookies[name] !== browserCookies[name]) {
|
|
||||||
//delete or reset all cookies that the browser dropped from $cookies
|
|
||||||
if (isUndefined(browserCookies[name])) {
|
|
||||||
delete cookies[name];
|
|
||||||
} else {
|
|
||||||
cookies[name] = browserCookies[name];
|
|
||||||
}
|
|
||||||
updated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}]).
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name ngCookies.$cookieStore
|
|
||||||
* @requires $cookies
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Provides a key-value (string-object) storage, that is backed by session cookies.
|
|
||||||
* Objects put or retrieved from this storage are automatically serialized or
|
|
||||||
* deserialized by angular's toJson/fromJson.
|
|
||||||
* @example
|
|
||||||
*/
|
|
||||||
factory('$cookieStore', ['$cookies', function($cookies) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name ngCookies.$cookieStore#get
|
|
||||||
* @methodOf ngCookies.$cookieStore
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Returns the value of given cookie key
|
|
||||||
*
|
|
||||||
* @param {string} key Id to use for lookup.
|
|
||||||
* @returns {Object} Deserialized cookie value.
|
|
||||||
*/
|
|
||||||
get: function(key) {
|
|
||||||
var value = $cookies[key];
|
|
||||||
return value ? angular.fromJson(value) : value;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name ngCookies.$cookieStore#put
|
|
||||||
* @methodOf ngCookies.$cookieStore
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Sets a value for given cookie key
|
|
||||||
*
|
|
||||||
* @param {string} key Id for the `value`.
|
|
||||||
* @param {Object} value Value to be stored.
|
|
||||||
*/
|
|
||||||
put: function(key, value) {
|
|
||||||
$cookies[key] = angular.toJson(value);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name ngCookies.$cookieStore#remove
|
|
||||||
* @methodOf ngCookies.$cookieStore
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Remove given cookie
|
|
||||||
*
|
|
||||||
* @param {string} key Id of the key-value pair to delete.
|
|
||||||
*/
|
|
||||||
remove: function(key) {
|
|
||||||
delete $cookies[key];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}]);
|
|
||||||
|
|
||||||
|
|
||||||
})(window, window.angular);
|
|
|
@ -1,277 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.0.7
|
|
||||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
(
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc interface
|
|
||||||
* @name angular.Module
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* Interface for configuring angular {@link angular.module modules}.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function setupModuleLoader(window) {
|
|
||||||
|
|
||||||
function ensure(obj, name, factory) {
|
|
||||||
return obj[name] || (obj[name] = factory());
|
|
||||||
}
|
|
||||||
|
|
||||||
return ensure(ensure(window, 'angular', Object), 'module', function() {
|
|
||||||
/** @type {Object.<string, angular.Module>} */
|
|
||||||
var modules = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name angular.module
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
* The `angular.module` is a global place for creating and registering Angular modules. All
|
|
||||||
* modules (angular core or 3rd party) that should be available to an application must be
|
|
||||||
* registered using this mechanism.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* # Module
|
|
||||||
*
|
|
||||||
* A module is a collocation of services, directives, filters, and configuration information. Module
|
|
||||||
* is used to configure the {@link AUTO.$injector $injector}.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* // Create a new module
|
|
||||||
* var myModule = angular.module('myModule', []);
|
|
||||||
*
|
|
||||||
* // register a new service
|
|
||||||
* myModule.value('appName', 'MyCoolApp');
|
|
||||||
*
|
|
||||||
* // configure existing services inside initialization blocks.
|
|
||||||
* myModule.config(function($locationProvider) {
|
|
||||||
'use strict';
|
|
||||||
* // Configure existing providers
|
|
||||||
* $locationProvider.hashPrefix('!');
|
|
||||||
* });
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* Then you can create an injector and load your modules like this:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* var injector = angular.injector(['ng', 'MyModule'])
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* However it's more likely that you'll just use
|
|
||||||
* {@link ng.directive:ngApp ngApp} or
|
|
||||||
* {@link angular.bootstrap} to simplify this process for you.
|
|
||||||
*
|
|
||||||
* @param {!string} name The name of the module to create or retrieve.
|
|
||||||
* @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
|
|
||||||
* the module is being retrieved for further configuration.
|
|
||||||
* @param {Function} configFn Optional configuration function for the module. Same as
|
|
||||||
* {@link angular.Module#config Module#config()}.
|
|
||||||
* @returns {module} new module with the {@link angular.Module} api.
|
|
||||||
*/
|
|
||||||
return function module(name, requires, configFn) {
|
|
||||||
if (requires && modules.hasOwnProperty(name)) {
|
|
||||||
modules[name] = null;
|
|
||||||
}
|
|
||||||
return ensure(modules, name, function() {
|
|
||||||
if (!requires) {
|
|
||||||
throw Error('No module: ' + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {!Array.<Array.<*>>} */
|
|
||||||
var invokeQueue = [];
|
|
||||||
|
|
||||||
/** @type {!Array.<Function>} */
|
|
||||||
var runBlocks = [];
|
|
||||||
|
|
||||||
var config = invokeLater('$injector', 'invoke');
|
|
||||||
|
|
||||||
/** @type {angular.Module} */
|
|
||||||
var moduleInstance = {
|
|
||||||
// Private state
|
|
||||||
_invokeQueue: invokeQueue,
|
|
||||||
_runBlocks: runBlocks,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc property
|
|
||||||
* @name angular.Module#requires
|
|
||||||
* @propertyOf angular.Module
|
|
||||||
* @returns {Array.<string>} List of module names which must be loaded before this module.
|
|
||||||
* @description
|
|
||||||
* Holds the list of modules which the injector will load before the current module is loaded.
|
|
||||||
*/
|
|
||||||
requires: requires,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc property
|
|
||||||
* @name angular.Module#name
|
|
||||||
* @propertyOf angular.Module
|
|
||||||
* @returns {string} Name of the module.
|
|
||||||
* @description
|
|
||||||
*/
|
|
||||||
name: name,
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#provider
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {Function} providerType Construction function for creating new instance of the service.
|
|
||||||
* @description
|
|
||||||
* See {@link AUTO.$provide#provider $provide.provider()}.
|
|
||||||
*/
|
|
||||||
provider: invokeLater('$provide', 'provider'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#factory
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {Function} providerFunction Function for creating new instance of the service.
|
|
||||||
* @description
|
|
||||||
* See {@link AUTO.$provide#factory $provide.factory()}.
|
|
||||||
*/
|
|
||||||
factory: invokeLater('$provide', 'factory'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#service
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {Function} constructor A constructor function that will be instantiated.
|
|
||||||
* @description
|
|
||||||
* See {@link AUTO.$provide#service $provide.service()}.
|
|
||||||
*/
|
|
||||||
service: invokeLater('$provide', 'service'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#value
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name service name
|
|
||||||
* @param {*} object Service instance object.
|
|
||||||
* @description
|
|
||||||
* See {@link AUTO.$provide#value $provide.value()}.
|
|
||||||
*/
|
|
||||||
value: invokeLater('$provide', 'value'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#constant
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name constant name
|
|
||||||
* @param {*} object Constant value.
|
|
||||||
* @description
|
|
||||||
* Because the constant are fixed, they get applied before other provide methods.
|
|
||||||
* See {@link AUTO.$provide#constant $provide.constant()}.
|
|
||||||
*/
|
|
||||||
constant: invokeLater('$provide', 'constant', 'unshift'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#filter
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name Filter name.
|
|
||||||
* @param {Function} filterFactory Factory function for creating new instance of filter.
|
|
||||||
* @description
|
|
||||||
* See {@link ng.$filterProvider#register $filterProvider.register()}.
|
|
||||||
*/
|
|
||||||
filter: invokeLater('$filterProvider', 'register'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#controller
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name Controller name.
|
|
||||||
* @param {Function} constructor Controller constructor function.
|
|
||||||
* @description
|
|
||||||
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
|
|
||||||
*/
|
|
||||||
controller: invokeLater('$controllerProvider', 'register'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#directive
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {string} name directive name
|
|
||||||
* @param {Function} directiveFactory Factory function for creating new instance of
|
|
||||||
* directives.
|
|
||||||
* @description
|
|
||||||
* See {@link ng.$compileProvider#directive $compileProvider.directive()}.
|
|
||||||
*/
|
|
||||||
directive: invokeLater('$compileProvider', 'directive'),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#config
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {Function} configFn Execute this function on module load. Useful for service
|
|
||||||
* configuration.
|
|
||||||
* @description
|
|
||||||
* Use this method to register work which needs to be performed on module loading.
|
|
||||||
*/
|
|
||||||
config: config,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name angular.Module#run
|
|
||||||
* @methodOf angular.Module
|
|
||||||
* @param {Function} initializationFn Execute this function after injector creation.
|
|
||||||
* Useful for application initialization.
|
|
||||||
* @description
|
|
||||||
* Use this method to register work which should be performed when the injector is done
|
|
||||||
* loading all modules.
|
|
||||||
*/
|
|
||||||
run: function(block) {
|
|
||||||
runBlocks.push(block);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (configFn) {
|
|
||||||
config(configFn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return moduleInstance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} provider
|
|
||||||
* @param {string} method
|
|
||||||
* @param {String=} insertMethod
|
|
||||||
* @returns {angular.Module}
|
|
||||||
*/
|
|
||||||
function invokeLater(provider, method, insertMethod) {
|
|
||||||
return function() {
|
|
||||||
invokeQueue[insertMethod || 'push']([provider, method, arguments]);
|
|
||||||
return moduleInstance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
)(window);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closure compiler type information
|
|
||||||
*
|
|
||||||
* @typedef { {
|
|
||||||
* requires: !Array.<string>,
|
|
||||||
* invokeQueue: !Array.<Array.<*>>,
|
|
||||||
*
|
|
||||||
* service: function(string, Function):angular.Module,
|
|
||||||
* factory: function(string, Function):angular.Module,
|
|
||||||
* value: function(string, *):angular.Module,
|
|
||||||
*
|
|
||||||
* filter: function(string, Function):angular.Module,
|
|
||||||
*
|
|
||||||
* init: function(Function):angular.Module
|
|
||||||
* } }
|
|
||||||
*/
|
|
||||||
angular.Module;
|
|
||||||
|
|
|
@ -1,457 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.0.7
|
|
||||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window, angular, undefined) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc overview
|
|
||||||
* @name ngResource
|
|
||||||
* @description
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc object
|
|
||||||
* @name ngResource.$resource
|
|
||||||
* @requires $http
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* A factory which creates a resource object that lets you interact with
|
|
||||||
* [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
|
|
||||||
*
|
|
||||||
* The returned resource object has action methods which provide high-level behaviors without
|
|
||||||
* the need to interact with the low level {@link ng.$http $http} service.
|
|
||||||
*
|
|
||||||
* # Installation
|
|
||||||
* To use $resource make sure you have included the `angular-resource.js` that comes in Angular
|
|
||||||
* package. You can also find this file on Google CDN, bower as well as at
|
|
||||||
* {@link http://code.angularjs.org/ code.angularjs.org}.
|
|
||||||
*
|
|
||||||
* Finally load the module in your application:
|
|
||||||
*
|
|
||||||
* angular.module('app', ['ngResource']);
|
|
||||||
*
|
|
||||||
* and you are ready to get started!
|
|
||||||
*
|
|
||||||
* @param {string} url A parameterized URL template with parameters prefixed by `:` as in
|
|
||||||
* `/user/:username`. If you are using a URL with a port number (e.g.
|
|
||||||
* `http://example.com:8080/api`), you'll need to escape the colon character before the port
|
|
||||||
* number, like this: `$resource('http://example.com\\:8080/api')`.
|
|
||||||
*
|
|
||||||
* @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
|
|
||||||
* `actions` methods.
|
|
||||||
*
|
|
||||||
* Each key value in the parameter object is first bound to url template if present and then any
|
|
||||||
* excess keys are appended to the url search query after the `?`.
|
|
||||||
*
|
|
||||||
* Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
|
|
||||||
* URL `/path/greet?salutation=Hello`.
|
|
||||||
*
|
|
||||||
* If the parameter value is prefixed with `@` then the value of that parameter is extracted from
|
|
||||||
* the data object (useful for non-GET operations).
|
|
||||||
*
|
|
||||||
* @param {Object.<Object>=} actions Hash with declaration of custom action that should extend the
|
|
||||||
* default set of resource actions. The declaration should be created in the following format:
|
|
||||||
*
|
|
||||||
* {action1: {method:?, params:?, isArray:?},
|
|
||||||
* action2: {method:?, params:?, isArray:?},
|
|
||||||
* ...}
|
|
||||||
*
|
|
||||||
* Where:
|
|
||||||
*
|
|
||||||
* - `action` – {string} – The name of action. This name becomes the name of the method on your
|
|
||||||
* resource object.
|
|
||||||
* - `method` – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`, `DELETE`,
|
|
||||||
* and `JSONP`
|
|
||||||
* - `params` – {object=} – Optional set of pre-bound parameters for this action.
|
|
||||||
* - isArray – {boolean=} – If true then the returned object for this action is an array, see
|
|
||||||
* `returns` section.
|
|
||||||
*
|
|
||||||
* @returns {Object} A resource "class" object with methods for the default set of resource actions
|
|
||||||
* optionally extended with custom `actions`. The default set contains these actions:
|
|
||||||
*
|
|
||||||
* { 'get': {method:'GET'},
|
|
||||||
* 'save': {method:'POST'},
|
|
||||||
* 'query': {method:'GET', isArray:true},
|
|
||||||
* 'remove': {method:'DELETE'},
|
|
||||||
* 'delete': {method:'DELETE'} };
|
|
||||||
*
|
|
||||||
* Calling these methods invoke an {@link ng.$http} with the specified http method,
|
|
||||||
* destination and parameters. When the data is returned from the server then the object is an
|
|
||||||
* instance of the resource class. The actions `save`, `remove` and `delete` are available on it
|
|
||||||
* as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
|
|
||||||
* read, update, delete) on server-side data like this:
|
|
||||||
* <pre>
|
|
||||||
var User = $resource('/user/:userId', {userId:'@id'});
|
|
||||||
var user = User.get({userId:123}, function() {
|
|
||||||
user.abc = true;
|
|
||||||
user.$save();
|
|
||||||
});
|
|
||||||
</pre>
|
|
||||||
*
|
|
||||||
* It is important to realize that invoking a $resource object method immediately returns an
|
|
||||||
* empty reference (object or array depending on `isArray`). Once the data is returned from the
|
|
||||||
* server the existing reference is populated with the actual data. This is a useful trick since
|
|
||||||
* usually the resource is assigned to a model which is then rendered by the view. Having an empty
|
|
||||||
* object results in no rendering, once the data arrives from the server then the object is
|
|
||||||
* populated with the data and the view automatically re-renders itself showing the new data. This
|
|
||||||
* means that in most case one never has to write a callback function for the action methods.
|
|
||||||
*
|
|
||||||
* The action methods on the class object or instance object can be invoked with the following
|
|
||||||
* parameters:
|
|
||||||
*
|
|
||||||
* - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
|
|
||||||
* - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
|
|
||||||
* - non-GET instance actions: `instance.$action([parameters], [success], [error])`
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* # Credit card resource
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
// Define CreditCard class
|
|
||||||
var CreditCard = $resource('/user/:userId/card/:cardId',
|
|
||||||
{userId:123, cardId:'@id'}, {
|
|
||||||
charge: {method:'POST', params:{charge:true}}
|
|
||||||
});
|
|
||||||
|
|
||||||
// We can retrieve a collection from the server
|
|
||||||
var cards = CreditCard.query(function() {
|
|
||||||
// GET: /user/123/card
|
|
||||||
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
|
|
||||||
|
|
||||||
var card = cards[0];
|
|
||||||
// each item is an instance of CreditCard
|
|
||||||
expect(card instanceof CreditCard).toEqual(true);
|
|
||||||
card.name = "J. Smith";
|
|
||||||
// non GET methods are mapped onto the instances
|
|
||||||
card.$save();
|
|
||||||
// POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
|
|
||||||
// server returns: {id:456, number:'1234', name: 'J. Smith'};
|
|
||||||
|
|
||||||
// our custom method is mapped as well.
|
|
||||||
card.$charge({amount:9.99});
|
|
||||||
// POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
|
|
||||||
});
|
|
||||||
|
|
||||||
// we can create an instance as well
|
|
||||||
var newCard = new CreditCard({number:'0123'});
|
|
||||||
newCard.name = "Mike Smith";
|
|
||||||
newCard.$save();
|
|
||||||
// POST: /user/123/card {number:'0123', name:'Mike Smith'}
|
|
||||||
// server returns: {id:789, number:'01234', name: 'Mike Smith'};
|
|
||||||
expect(newCard.id).toEqual(789);
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* The object returned from this function execution is a resource "class" which has "static" method
|
|
||||||
* for each action in the definition.
|
|
||||||
*
|
|
||||||
* Calling these methods invoke `$http` on the `url` template with the given `method` and `params`.
|
|
||||||
* When the data is returned from the server then the object is an instance of the resource type and
|
|
||||||
* all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
|
|
||||||
* operations (create, read, update, delete) on server-side data.
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
var User = $resource('/user/:userId', {userId:'@id'});
|
|
||||||
var user = User.get({userId:123}, function() {
|
|
||||||
user.abc = true;
|
|
||||||
user.$save();
|
|
||||||
});
|
|
||||||
</pre>
|
|
||||||
*
|
|
||||||
* It's worth noting that the success callback for `get`, `query` and other method gets passed
|
|
||||||
* in the response that came from the server as well as $http header getter function, so one
|
|
||||||
* could rewrite the above example and get access to http headers as:
|
|
||||||
*
|
|
||||||
<pre>
|
|
||||||
var User = $resource('/user/:userId', {userId:'@id'});
|
|
||||||
User.get({userId:123}, function(u, getResponseHeaders){
|
|
||||||
u.abc = true;
|
|
||||||
u.$save(function(u, putResponseHeaders) {
|
|
||||||
//u => saved user object
|
|
||||||
//putResponseHeaders => $http header getter
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
* # Buzz client
|
|
||||||
|
|
||||||
Let's look at what a buzz client created with the `$resource` service looks like:
|
|
||||||
<doc:example>
|
|
||||||
<doc:source jsfiddle="false">
|
|
||||||
<script>
|
|
||||||
function BuzzController($resource) {
|
|
||||||
this.userId = 'googlebuzz';
|
|
||||||
this.Activity = $resource(
|
|
||||||
'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments',
|
|
||||||
{alt:'json', callback:'JSON_CALLBACK'},
|
|
||||||
{get:{method:'JSONP', params:{visibility:'@self'}}, replies: {method:'JSONP', params:{visibility:'@self', comments:'@comments'}}}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
BuzzController.prototype = {
|
|
||||||
fetch: function() {
|
|
||||||
this.activities = this.Activity.get({userId:this.userId});
|
|
||||||
},
|
|
||||||
expandReplies: function(activity) {
|
|
||||||
activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
BuzzController.$inject = ['$resource'];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div ng-controller="BuzzController">
|
|
||||||
<input ng-model="userId"/>
|
|
||||||
<button ng-click="fetch()">fetch</button>
|
|
||||||
<hr/>
|
|
||||||
<div ng-repeat="item in activities.data.items">
|
|
||||||
<h1 style="font-size: 15px;">
|
|
||||||
<img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
|
|
||||||
<a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
|
|
||||||
<a href ng-click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a>
|
|
||||||
</h1>
|
|
||||||
{{item.object.content | html}}
|
|
||||||
<div ng-repeat="reply in item.replies.data.items" style="margin-left: 20px;">
|
|
||||||
<img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
|
|
||||||
<a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>
|
|
||||||
</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
*/
|
|
||||||
angular.module('ngResource', ['ng']).
|
|
||||||
factory('$resource', ['$http', '$parse', function($http, $parse) {
|
|
||||||
var DEFAULT_ACTIONS = {
|
|
||||||
'get': {method:'GET'},
|
|
||||||
'save': {method:'POST'},
|
|
||||||
'query': {method:'GET', isArray:true},
|
|
||||||
'remove': {method:'DELETE'},
|
|
||||||
'delete': {method:'DELETE'}
|
|
||||||
};
|
|
||||||
var noop = angular.noop,
|
|
||||||
forEach = angular.forEach,
|
|
||||||
extend = angular.extend,
|
|
||||||
copy = angular.copy,
|
|
||||||
isFunction = angular.isFunction,
|
|
||||||
getter = function(obj, path) {
|
|
||||||
return $parse(path)(obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We need our custom method because encodeURIComponent is too aggressive and doesn't follow
|
|
||||||
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
|
|
||||||
* segments:
|
|
||||||
* segment = *pchar
|
|
||||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
||||||
* pct-encoded = "%" HEXDIG HEXDIG
|
|
||||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
|
||||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
|
||||||
* / "*" / "+" / "," / ";" / "="
|
|
||||||
*/
|
|
||||||
function encodeUriSegment(val) {
|
|
||||||
return encodeUriQuery(val, true).
|
|
||||||
replace(/%26/gi, '&').
|
|
||||||
replace(/%3D/gi, '=').
|
|
||||||
replace(/%2B/gi, '+');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
|
||||||
* method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
|
|
||||||
* encoded per http://tools.ietf.org/html/rfc3986:
|
|
||||||
* query = *( pchar / "/" / "?" )
|
|
||||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
||||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
|
||||||
* pct-encoded = "%" HEXDIG HEXDIG
|
|
||||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
|
||||||
* / "*" / "+" / "," / ";" / "="
|
|
||||||
*/
|
|
||||||
function encodeUriQuery(val, pctEncodeSpaces) {
|
|
||||||
return encodeURIComponent(val).
|
|
||||||
replace(/%40/gi, '@').
|
|
||||||
replace(/%3A/gi, ':').
|
|
||||||
replace(/%24/g, '$').
|
|
||||||
replace(/%2C/gi, ',').
|
|
||||||
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function Route(template, defaults) {
|
|
||||||
this.template = template = template + '#';
|
|
||||||
this.defaults = defaults || {};
|
|
||||||
var urlParams = this.urlParams = {};
|
|
||||||
forEach(template.split(/\W/), function(param){
|
|
||||||
if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(template))) {
|
|
||||||
urlParams[param] = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.template = template.replace(/\\:/g, ':');
|
|
||||||
}
|
|
||||||
|
|
||||||
Route.prototype = {
|
|
||||||
url: function(params) {
|
|
||||||
var self = this,
|
|
||||||
url = this.template,
|
|
||||||
val,
|
|
||||||
encodedVal;
|
|
||||||
|
|
||||||
params = params || {};
|
|
||||||
forEach(this.urlParams, function(_, urlParam){
|
|
||||||
val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
|
|
||||||
if (angular.isDefined(val) && val !== null) {
|
|
||||||
encodedVal = encodeUriSegment(val);
|
|
||||||
url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
|
|
||||||
} else {
|
|
||||||
url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W)", "g"), function(match,
|
|
||||||
leadingSlashes, tail) {
|
|
||||||
if (tail.charAt(0) == '/') {
|
|
||||||
return tail;
|
|
||||||
} else {
|
|
||||||
return leadingSlashes + tail;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
url = url.replace(/\/?#$/, '');
|
|
||||||
var query = [];
|
|
||||||
forEach(params, function(value, key){
|
|
||||||
if (!self.urlParams[key]) {
|
|
||||||
query.push(encodeUriQuery(key) + '=' + encodeUriQuery(value));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
query.sort();
|
|
||||||
url = url.replace(/\/*$/, '');
|
|
||||||
return url + (query.length ? '?' + query.join('&') : '');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function ResourceFactory(url, paramDefaults, actions) {
|
|
||||||
var route = new Route(url);
|
|
||||||
|
|
||||||
actions = extend({}, DEFAULT_ACTIONS, actions);
|
|
||||||
|
|
||||||
function extractParams(data, actionParams){
|
|
||||||
var ids = {};
|
|
||||||
actionParams = extend({}, paramDefaults, actionParams);
|
|
||||||
forEach(actionParams, function(value, key){
|
|
||||||
ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
|
|
||||||
});
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Resource(value){
|
|
||||||
copy(value || {}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
forEach(actions, function(action, name) {
|
|
||||||
action.method = angular.uppercase(action.method);
|
|
||||||
var hasBody = action.method == 'POST' || action.method == 'PUT' || action.method == 'PATCH';
|
|
||||||
Resource[name] = function(a1, a2, a3, a4) {
|
|
||||||
var params = {};
|
|
||||||
var data;
|
|
||||||
var success = noop;
|
|
||||||
var error = null;
|
|
||||||
switch(arguments.length) {
|
|
||||||
case 4:
|
|
||||||
error = a4;
|
|
||||||
success = a3;
|
|
||||||
//fallthrough
|
|
||||||
case 3:
|
|
||||||
case 2:
|
|
||||||
if (isFunction(a2)) {
|
|
||||||
if (isFunction(a1)) {
|
|
||||||
success = a1;
|
|
||||||
error = a2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
success = a2;
|
|
||||||
error = a3;
|
|
||||||
//fallthrough
|
|
||||||
} else {
|
|
||||||
params = a1;
|
|
||||||
data = a2;
|
|
||||||
success = a3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
if (isFunction(a1)) success = a1;
|
|
||||||
else if (hasBody) data = a1;
|
|
||||||
else params = a1;
|
|
||||||
break;
|
|
||||||
case 0: break;
|
|
||||||
default:
|
|
||||||
throw "Expected between 0-4 arguments [params, data, success, error], got " +
|
|
||||||
arguments.length + " arguments.";
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));
|
|
||||||
$http({
|
|
||||||
method: action.method,
|
|
||||||
url: route.url(extend({}, extractParams(data, action.params || {}), params)),
|
|
||||||
data: data
|
|
||||||
}).then(function(response) {
|
|
||||||
var data = response.data;
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
if (action.isArray) {
|
|
||||||
value.length = 0;
|
|
||||||
forEach(data, function(item) {
|
|
||||||
value.push(new Resource(item));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
copy(data, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(success||noop)(value, response.headers);
|
|
||||||
}, error);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Resource.prototype['$' + name] = function(a1, a2, a3) {
|
|
||||||
var params = extractParams(this),
|
|
||||||
success = noop,
|
|
||||||
error;
|
|
||||||
|
|
||||||
switch(arguments.length) {
|
|
||||||
case 3: params = a1; success = a2; error = a3; break;
|
|
||||||
case 2:
|
|
||||||
case 1:
|
|
||||||
if (isFunction(a1)) {
|
|
||||||
success = a1;
|
|
||||||
error = a2;
|
|
||||||
} else {
|
|
||||||
params = a1;
|
|
||||||
success = a2 || noop;
|
|
||||||
}
|
|
||||||
case 0: break;
|
|
||||||
default:
|
|
||||||
throw "Expected between 1-3 arguments [params, success, error], got " +
|
|
||||||
arguments.length + " arguments.";
|
|
||||||
}
|
|
||||||
var data = hasBody ? this : undefined;
|
|
||||||
Resource[name].call(this, params, data, success, error);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
Resource.bind = function(additionalParamDefaults){
|
|
||||||
return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
|
|
||||||
};
|
|
||||||
|
|
||||||
return Resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResourceFactory;
|
|
||||||
}]);
|
|
||||||
|
|
||||||
|
|
||||||
})(window, window.angular);
|
|
|
@ -1,537 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.0.7
|
|
||||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window, angular, undefined) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc overview
|
|
||||||
* @name ngSanitize
|
|
||||||
* @description
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* HTML Parser By Misko Hevery (misko@hevery.com)
|
|
||||||
* based on: HTML Parser By John Resig (ejohn.org)
|
|
||||||
* Original code by Erik Arvidsson, Mozilla Public License
|
|
||||||
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
|
||||||
*
|
|
||||||
* // Use like so:
|
|
||||||
* htmlParser(htmlString, {
|
|
||||||
* start: function(tag, attrs, unary) {},
|
|
||||||
* end: function(tag) {},
|
|
||||||
* chars: function(text) {},
|
|
||||||
* comment: function(text) {}
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc service
|
|
||||||
* @name ngSanitize.$sanitize
|
|
||||||
* @function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are
|
|
||||||
* then serialized back to properly escaped html string. This means that no unsafe input can make
|
|
||||||
* it into the returned string, however, since our parser is more strict than a typical browser
|
|
||||||
* parser, it's possible that some obscure input, which would be recognized as valid HTML by a
|
|
||||||
* browser, won't make it through the sanitizer.
|
|
||||||
*
|
|
||||||
* @param {string} html Html input.
|
|
||||||
* @returns {string} Sanitized html.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
<doc:example module="ngSanitize">
|
|
||||||
<doc:source>
|
|
||||||
<script>
|
|
||||||
function Ctrl($scope) {
|
|
||||||
$scope.snippet =
|
|
||||||
'<p style="color:blue">an html\n' +
|
|
||||||
'<em onmouseover="this.textContent=\'PWN3D!\'">click here</em>\n' +
|
|
||||||
'snippet</p>';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div ng-controller="Ctrl">
|
|
||||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Filter</td>
|
|
||||||
<td>Source</td>
|
|
||||||
<td>Rendered</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="html-filter">
|
|
||||||
<td>html filter</td>
|
|
||||||
<td>
|
|
||||||
<pre><div ng-bind-html="snippet"><br/></div></pre>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div ng-bind-html="snippet"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="escaped-html">
|
|
||||||
<td>no filter</td>
|
|
||||||
<td><pre><div ng-bind="snippet"><br/></div></pre></td>
|
|
||||||
<td><div ng-bind="snippet"></div></td>
|
|
||||||
</tr>
|
|
||||||
<tr id="html-unsafe-filter">
|
|
||||||
<td>unsafe html filter</td>
|
|
||||||
<td><pre><div ng-bind-html-unsafe="snippet"><br/></div></pre></td>
|
|
||||||
<td><div ng-bind-html-unsafe="snippet"></div></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>
|
|
||||||
it('should sanitize the html snippet ', function() {
|
|
||||||
expect(using('#html-filter').element('div').html()).
|
|
||||||
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should escape snippet without any filter', function() {
|
|
||||||
expect(using('#escaped-html').element('div').html()).
|
|
||||||
toBe("<p style=\"color:blue\">an html\n" +
|
|
||||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
|
||||||
"snippet</p>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should inline raw snippet if filtered as unsafe', function() {
|
|
||||||
expect(using('#html-unsafe-filter').element("div").html()).
|
|
||||||
toBe("<p style=\"color:blue\">an html\n" +
|
|
||||||
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
|
|
||||||
"snippet</p>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update', function() {
|
|
||||||
input('snippet').enter('new <b>text</b>');
|
|
||||||
expect(using('#html-filter').binding('snippet')).toBe('new <b>text</b>');
|
|
||||||
expect(using('#escaped-html').element('div').html()).toBe("new <b>text</b>");
|
|
||||||
expect(using('#html-unsafe-filter').binding("snippet")).toBe('new <b>text</b>');
|
|
||||||
});
|
|
||||||
</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
*/
|
|
||||||
var $sanitize = function(html) {
|
|
||||||
var buf = [];
|
|
||||||
htmlParser(html, htmlSanitizeWriter(buf));
|
|
||||||
return buf.join('');
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Regular Expressions for parsing tags and attributes
|
|
||||||
var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/,
|
|
||||||
END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/,
|
|
||||||
ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,
|
|
||||||
BEGIN_TAG_REGEXP = /^</,
|
|
||||||
BEGING_END_TAGE_REGEXP = /^<\s*\//,
|
|
||||||
COMMENT_REGEXP = /<!--(.*?)-->/g,
|
|
||||||
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g,
|
|
||||||
URI_REGEXP = /^((ftp|https?):\/\/|mailto:|#)/,
|
|
||||||
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; // Match everything outside of normal chars and " (quote character)
|
|
||||||
|
|
||||||
|
|
||||||
// Good source of info about elements and attributes
|
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#semantics
|
|
||||||
// http://simon.html5.org/html-elements
|
|
||||||
|
|
||||||
// Safe Void Elements - HTML5
|
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#void-elements
|
|
||||||
var voidElements = makeMap("area,br,col,hr,img,wbr");
|
|
||||||
|
|
||||||
// Elements that you can, intentionally, leave open (and which close themselves)
|
|
||||||
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
|
|
||||||
var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
|
|
||||||
optionalEndTagInlineElements = makeMap("rp,rt"),
|
|
||||||
optionalEndTagElements = angular.extend({}, optionalEndTagInlineElements, optionalEndTagBlockElements);
|
|
||||||
|
|
||||||
// Safe Block Elements - HTML5
|
|
||||||
var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article,aside," +
|
|
||||||
"blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6," +
|
|
||||||
"header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul"));
|
|
||||||
|
|
||||||
// Inline Elements - HTML5
|
|
||||||
var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b,bdi,bdo," +
|
|
||||||
"big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small," +
|
|
||||||
"span,strike,strong,sub,sup,time,tt,u,var"));
|
|
||||||
|
|
||||||
|
|
||||||
// Special Elements (can contain anything)
|
|
||||||
var specialElements = makeMap("script,style");
|
|
||||||
|
|
||||||
var validElements = angular.extend({}, voidElements, blockElements, inlineElements, optionalEndTagElements);
|
|
||||||
|
|
||||||
//Attributes that have href and hence need to be sanitized
|
|
||||||
var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap");
|
|
||||||
var validAttrs = angular.extend({}, uriAttrs, makeMap(
|
|
||||||
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
|
|
||||||
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
|
|
||||||
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
|
|
||||||
'scope,scrolling,shape,span,start,summary,target,title,type,'+
|
|
||||||
'valign,value,vspace,width'));
|
|
||||||
|
|
||||||
function makeMap(str) {
|
|
||||||
var obj = {}, items = str.split(','), i;
|
|
||||||
for (i = 0; i < items.length; i++) obj[items[i]] = true;
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @example
|
|
||||||
* htmlParser(htmlString, {
|
|
||||||
* start: function(tag, attrs, unary) {},
|
|
||||||
* end: function(tag) {},
|
|
||||||
* chars: function(text) {},
|
|
||||||
* comment: function(text) {}
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* @param {string} html string
|
|
||||||
* @param {object} handler
|
|
||||||
*/
|
|
||||||
function htmlParser( html, handler ) {
|
|
||||||
var index, chars, match, stack = [], last = html;
|
|
||||||
stack.last = function() { return stack[ stack.length - 1 ]; };
|
|
||||||
|
|
||||||
while ( html ) {
|
|
||||||
chars = true;
|
|
||||||
|
|
||||||
// Make sure we're not in a script or style element
|
|
||||||
if ( !stack.last() || !specialElements[ stack.last() ] ) {
|
|
||||||
|
|
||||||
// Comment
|
|
||||||
if ( html.indexOf("<!--") === 0 ) {
|
|
||||||
index = html.indexOf("-->");
|
|
||||||
|
|
||||||
if ( index >= 0 ) {
|
|
||||||
if (handler.comment) handler.comment( html.substring( 4, index ) );
|
|
||||||
html = html.substring( index + 3 );
|
|
||||||
chars = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// end tag
|
|
||||||
} else if ( BEGING_END_TAGE_REGEXP.test(html) ) {
|
|
||||||
match = html.match( END_TAG_REGEXP );
|
|
||||||
|
|
||||||
if ( match ) {
|
|
||||||
html = html.substring( match[0].length );
|
|
||||||
match[0].replace( END_TAG_REGEXP, parseEndTag );
|
|
||||||
chars = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// start tag
|
|
||||||
} else if ( BEGIN_TAG_REGEXP.test(html) ) {
|
|
||||||
match = html.match( START_TAG_REGEXP );
|
|
||||||
|
|
||||||
if ( match ) {
|
|
||||||
html = html.substring( match[0].length );
|
|
||||||
match[0].replace( START_TAG_REGEXP, parseStartTag );
|
|
||||||
chars = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( chars ) {
|
|
||||||
index = html.indexOf("<");
|
|
||||||
|
|
||||||
var text = index < 0 ? html : html.substring( 0, index );
|
|
||||||
html = index < 0 ? "" : html.substring( index );
|
|
||||||
|
|
||||||
if (handler.chars) handler.chars( decodeEntities(text) );
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
html = html.replace(new RegExp("(.*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), function(all, text){
|
|
||||||
text = text.
|
|
||||||
replace(COMMENT_REGEXP, "$1").
|
|
||||||
replace(CDATA_REGEXP, "$1");
|
|
||||||
|
|
||||||
if (handler.chars) handler.chars( decodeEntities(text) );
|
|
||||||
|
|
||||||
return "";
|
|
||||||
});
|
|
||||||
|
|
||||||
parseEndTag( "", stack.last() );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( html == last ) {
|
|
||||||
throw "Parse Error: " + html;
|
|
||||||
}
|
|
||||||
last = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up any remaining tags
|
|
||||||
parseEndTag();
|
|
||||||
|
|
||||||
function parseStartTag( tag, tagName, rest, unary ) {
|
|
||||||
tagName = angular.lowercase(tagName);
|
|
||||||
if ( blockElements[ tagName ] ) {
|
|
||||||
while ( stack.last() && inlineElements[ stack.last() ] ) {
|
|
||||||
parseEndTag( "", stack.last() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( optionalEndTagElements[ tagName ] && stack.last() == tagName ) {
|
|
||||||
parseEndTag( "", tagName );
|
|
||||||
}
|
|
||||||
|
|
||||||
unary = voidElements[ tagName ] || !!unary;
|
|
||||||
|
|
||||||
if ( !unary )
|
|
||||||
stack.push( tagName );
|
|
||||||
|
|
||||||
var attrs = {};
|
|
||||||
|
|
||||||
rest.replace(ATTR_REGEXP, function(match, name, doubleQuotedValue, singleQoutedValue, unqoutedValue) {
|
|
||||||
var value = doubleQuotedValue
|
|
||||||
|| singleQoutedValue
|
|
||||||
|| unqoutedValue
|
|
||||||
|| '';
|
|
||||||
|
|
||||||
attrs[name] = decodeEntities(value);
|
|
||||||
});
|
|
||||||
if (handler.start) handler.start( tagName, attrs, unary );
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseEndTag( tag, tagName ) {
|
|
||||||
var pos = 0, i;
|
|
||||||
tagName = angular.lowercase(tagName);
|
|
||||||
if ( tagName )
|
|
||||||
// Find the closest opened tag of the same type
|
|
||||||
for ( pos = stack.length - 1; pos >= 0; pos-- )
|
|
||||||
if ( stack[ pos ] == tagName )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ( pos >= 0 ) {
|
|
||||||
// Close all the open elements, up the stack
|
|
||||||
for ( i = stack.length - 1; i >= pos; i-- )
|
|
||||||
if (handler.end) handler.end( stack[ i ] );
|
|
||||||
|
|
||||||
// Remove the open elements from the stack
|
|
||||||
stack.length = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* decodes all entities into regular string
|
|
||||||
* @param value
|
|
||||||
* @returns {string} A string with decoded entities.
|
|
||||||
*/
|
|
||||||
var hiddenPre=document.createElement("pre");
|
|
||||||
function decodeEntities(value) {
|
|
||||||
hiddenPre.innerHTML=value.replace(/</g,"<");
|
|
||||||
return hiddenPre.innerText || hiddenPre.textContent || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escapes all potentially dangerous characters, so that the
|
|
||||||
* resulting string can be safely inserted into attribute or
|
|
||||||
* element text.
|
|
||||||
* @param value
|
|
||||||
* @returns escaped text
|
|
||||||
*/
|
|
||||||
function encodeEntities(value) {
|
|
||||||
return value.
|
|
||||||
replace(/&/g, '&').
|
|
||||||
replace(NON_ALPHANUMERIC_REGEXP, function(value){
|
|
||||||
return '&#' + value.charCodeAt(0) + ';';
|
|
||||||
}).
|
|
||||||
replace(/</g, '<').
|
|
||||||
replace(/>/g, '>');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an HTML/XML writer which writes to buffer
|
|
||||||
* @param {Array} buf use buf.jain('') to get out sanitized html string
|
|
||||||
* @returns {object} in the form of {
|
|
||||||
* start: function(tag, attrs, unary) {},
|
|
||||||
* end: function(tag) {},
|
|
||||||
* chars: function(text) {},
|
|
||||||
* comment: function(text) {}
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
function htmlSanitizeWriter(buf){
|
|
||||||
var ignore = false;
|
|
||||||
var out = angular.bind(buf, buf.push);
|
|
||||||
return {
|
|
||||||
start: function(tag, attrs, unary){
|
|
||||||
tag = angular.lowercase(tag);
|
|
||||||
if (!ignore && specialElements[tag]) {
|
|
||||||
ignore = tag;
|
|
||||||
}
|
|
||||||
if (!ignore && validElements[tag] == true) {
|
|
||||||
out('<');
|
|
||||||
out(tag);
|
|
||||||
angular.forEach(attrs, function(value, key){
|
|
||||||
var lkey=angular.lowercase(key);
|
|
||||||
if (validAttrs[lkey]==true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) {
|
|
||||||
out(' ');
|
|
||||||
out(key);
|
|
||||||
out('="');
|
|
||||||
out(encodeEntities(value));
|
|
||||||
out('"');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
out(unary ? '/>' : '>');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
end: function(tag){
|
|
||||||
tag = angular.lowercase(tag);
|
|
||||||
if (!ignore && validElements[tag] == true) {
|
|
||||||
out('</');
|
|
||||||
out(tag);
|
|
||||||
out('>');
|
|
||||||
}
|
|
||||||
if (tag == ignore) {
|
|
||||||
ignore = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
chars: function(chars){
|
|
||||||
if (!ignore) {
|
|
||||||
out(encodeEntities(chars));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// define ngSanitize module and register $sanitize service
|
|
||||||
angular.module('ngSanitize', []).value('$sanitize', $sanitize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc directive
|
|
||||||
* @name ngSanitize.directive:ngBindHtml
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Creates a binding that will sanitize the result of evaluating the `expression` with the
|
|
||||||
* {@link ngSanitize.$sanitize $sanitize} service and innerHTML the result into the current element.
|
|
||||||
*
|
|
||||||
* See {@link ngSanitize.$sanitize $sanitize} docs for examples.
|
|
||||||
*
|
|
||||||
* @element ANY
|
|
||||||
* @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
|
|
||||||
*/
|
|
||||||
angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($sanitize) {
|
|
||||||
return function(scope, element, attr) {
|
|
||||||
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
|
|
||||||
scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) {
|
|
||||||
value = $sanitize(value);
|
|
||||||
element.html(value || '');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc filter
|
|
||||||
* @name ngSanitize.filter:linky
|
|
||||||
* @function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and
|
|
||||||
* plain email address links.
|
|
||||||
*
|
|
||||||
* @param {string} text Input text.
|
|
||||||
* @returns {string} Html-linkified text.
|
|
||||||
*
|
|
||||||
* @usage
|
|
||||||
<span ng-bind-html="linky_expression | linky"></span>
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
<doc:example module="ngSanitize">
|
|
||||||
<doc:source>
|
|
||||||
<script>
|
|
||||||
function Ctrl($scope) {
|
|
||||||
$scope.snippet =
|
|
||||||
'Pretty text with some links:\n'+
|
|
||||||
'http://angularjs.org/,\n'+
|
|
||||||
'mailto:us@somewhere.org,\n'+
|
|
||||||
'another@somewhere.org,\n'+
|
|
||||||
'and one more: ftp://127.0.0.1/.';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div ng-controller="Ctrl">
|
|
||||||
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Filter</td>
|
|
||||||
<td>Source</td>
|
|
||||||
<td>Rendered</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="linky-filter">
|
|
||||||
<td>linky filter</td>
|
|
||||||
<td>
|
|
||||||
<pre><div ng-bind-html="snippet | linky"><br></div></pre>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div ng-bind-html="snippet | linky"></div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr id="escaped-html">
|
|
||||||
<td>no filter</td>
|
|
||||||
<td><pre><div ng-bind="snippet"><br></div></pre></td>
|
|
||||||
<td><div ng-bind="snippet"></div></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>
|
|
||||||
it('should linkify the snippet with urls', function() {
|
|
||||||
expect(using('#linky-filter').binding('snippet | linky')).
|
|
||||||
toBe('Pretty text with some links: ' +
|
|
||||||
'<a href="http://angularjs.org/">http://angularjs.org/</a>, ' +
|
|
||||||
'<a href="mailto:us@somewhere.org">us@somewhere.org</a>, ' +
|
|
||||||
'<a href="mailto:another@somewhere.org">another@somewhere.org</a>, ' +
|
|
||||||
'and one more: <a href="ftp://127.0.0.1/">ftp://127.0.0.1/</a>.');
|
|
||||||
});
|
|
||||||
|
|
||||||
it ('should not linkify snippet without the linky filter', function() {
|
|
||||||
expect(using('#escaped-html').binding('snippet')).
|
|
||||||
toBe("Pretty text with some links:\n" +
|
|
||||||
"http://angularjs.org/,\n" +
|
|
||||||
"mailto:us@somewhere.org,\n" +
|
|
||||||
"another@somewhere.org,\n" +
|
|
||||||
"and one more: ftp://127.0.0.1/.");
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update', function() {
|
|
||||||
input('snippet').enter('new http://link.');
|
|
||||||
expect(using('#linky-filter').binding('snippet | linky')).
|
|
||||||
toBe('new <a href="http://link">http://link</a>.');
|
|
||||||
expect(using('#escaped-html').binding('snippet')).toBe('new http://link.');
|
|
||||||
});
|
|
||||||
</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
*/
|
|
||||||
angular.module('ngSanitize').filter('linky', function() {
|
|
||||||
var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}\<\>]/,
|
|
||||||
MAILTO_REGEXP = /^mailto:/;
|
|
||||||
|
|
||||||
return function(text) {
|
|
||||||
if (!text) return text;
|
|
||||||
var match;
|
|
||||||
var raw = text;
|
|
||||||
var html = [];
|
|
||||||
// TODO(vojta): use $sanitize instead
|
|
||||||
var writer = htmlSanitizeWriter(html);
|
|
||||||
var url;
|
|
||||||
var i;
|
|
||||||
while ((match = raw.match(LINKY_URL_REGEXP))) {
|
|
||||||
// We can not end in these as they are sometimes found at the end of the sentence
|
|
||||||
url = match[0];
|
|
||||||
// if we did not match ftp/http/mailto then assume mailto
|
|
||||||
if (match[2] == match[3]) url = 'mailto:' + url;
|
|
||||||
i = match.index;
|
|
||||||
writer.chars(raw.substr(0, i));
|
|
||||||
writer.start('a', {href:url});
|
|
||||||
writer.chars(match[0].replace(MAILTO_REGEXP, ''));
|
|
||||||
writer.end('a');
|
|
||||||
raw = raw.substring(i + match[0].length);
|
|
||||||
}
|
|
||||||
writer.chars(raw);
|
|
||||||
return html.join('');
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})(window, window.angular);
|
|
|
@ -1,6 +0,0 @@
|
||||||
/**
|
|
||||||
* Configuration for jstd scenario adapter
|
|
||||||
*/
|
|
||||||
var jstdScenarioAdapter = {
|
|
||||||
relativeUrlPrefix: '/build/docs/'
|
|
||||||
};
|
|
|
@ -1,185 +0,0 @@
|
||||||
/**
|
|
||||||
* @license AngularJS v1.0.5
|
|
||||||
* (c) 2010-2012 Google, Inc. http://angularjs.org
|
|
||||||
* License: MIT
|
|
||||||
*/
|
|
||||||
(function(window) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSTestDriver adapter for angular scenario tests
|
|
||||||
*
|
|
||||||
* Example of jsTestDriver.conf for running scenario tests with JSTD:
|
|
||||||
<pre>
|
|
||||||
server: http://localhost:9877
|
|
||||||
|
|
||||||
load:
|
|
||||||
- lib/angular-scenario.js
|
|
||||||
- lib/jstd-scenario-adapter-config.js
|
|
||||||
- lib/jstd-scenario-adapter.js
|
|
||||||
# your test files go here #
|
|
||||||
|
|
||||||
proxy:
|
|
||||||
- {matcher: "/your-prefix/*", server: "http://localhost:8000/"}
|
|
||||||
</pre>
|
|
||||||
*
|
|
||||||
* For more information on how to configure jstd proxy, see {@link http://code.google.com/p/js-test-driver/wiki/Proxy}
|
|
||||||
* Note the order of files - it's important !
|
|
||||||
*
|
|
||||||
* Example of jstd-scenario-adapter-config.js
|
|
||||||
<pre>
|
|
||||||
var jstdScenarioAdapter = {
|
|
||||||
relativeUrlPrefix: '/your-prefix/'
|
|
||||||
};
|
|
||||||
</pre>
|
|
||||||
*
|
|
||||||
* Whenever you use <code>browser().navigateTo('relativeUrl')</code> in your scenario test, the relativeUrlPrefix will be prepended.
|
|
||||||
* You have to configure this to work together with JSTD proxy.
|
|
||||||
*
|
|
||||||
* Let's assume you are using the above configuration (jsTestDriver.conf and jstd-scenario-adapter-config.js):
|
|
||||||
* Now, when you call <code>browser().navigateTo('index.html')</code> in your scenario test, the browser will open /your-prefix/index.html.
|
|
||||||
* That matches the proxy, so JSTD will proxy this request to http://localhost:8000/index.html.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom type of test case
|
|
||||||
*
|
|
||||||
* @const
|
|
||||||
* @see jstestdriver.TestCaseInfo
|
|
||||||
*/
|
|
||||||
var SCENARIO_TYPE = 'scenario';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Plugin for JSTestDriver
|
|
||||||
* Connection point between scenario's jstd output and jstestdriver.
|
|
||||||
*
|
|
||||||
* @see jstestdriver.PluginRegistrar
|
|
||||||
*/
|
|
||||||
function JstdPlugin() {
|
|
||||||
var nop = function() {};
|
|
||||||
|
|
||||||
this.reportResult = nop;
|
|
||||||
this.reportEnd = nop;
|
|
||||||
this.runScenario = nop;
|
|
||||||
|
|
||||||
this.name = 'Angular Scenario Adapter';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called for each JSTD TestCase
|
|
||||||
*
|
|
||||||
* Handles only SCENARIO_TYPE test cases. There should be only one fake TestCase.
|
|
||||||
* Runs all scenario tests (under one fake TestCase) and report all results to JSTD.
|
|
||||||
*
|
|
||||||
* @param {jstestdriver.TestRunConfiguration} configuration
|
|
||||||
* @param {Function} onTestDone
|
|
||||||
* @param {Function} onAllTestsComplete
|
|
||||||
* @returns {boolean} True if this type of test is handled by this plugin, false otherwise
|
|
||||||
*/
|
|
||||||
this.runTestConfiguration = function(configuration, onTestDone, onAllTestsComplete) {
|
|
||||||
if (configuration.getTestCaseInfo().getType() != SCENARIO_TYPE) return false;
|
|
||||||
|
|
||||||
this.reportResult = onTestDone;
|
|
||||||
this.reportEnd = onAllTestsComplete;
|
|
||||||
this.runScenario();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getTestRunsConfigurationFor = function(testCaseInfos, expressions, testRunsConfiguration) {
|
|
||||||
testRunsConfiguration.push(
|
|
||||||
new jstestdriver.TestRunConfiguration(
|
|
||||||
new jstestdriver.TestCaseInfo(
|
|
||||||
'Angular Scenario Tests', function() {}, SCENARIO_TYPE), []));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Singleton instance of the plugin
|
|
||||||
* Accessed using closure by:
|
|
||||||
* - jstd output (reports to this plugin)
|
|
||||||
* - initScenarioAdapter (register the plugin to jstd)
|
|
||||||
*/
|
|
||||||
var plugin = new JstdPlugin();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise scenario jstd-adapter
|
|
||||||
* (only if jstestdriver is defined)
|
|
||||||
*
|
|
||||||
* @param {Object} jstestdriver Undefined when run from browser (without jstd)
|
|
||||||
* @param {Function} initScenarioAndRun Function that inits scenario and runs all the tests
|
|
||||||
* @param {Object=} config Configuration object, supported properties:
|
|
||||||
* - relativeUrlPrefix: prefix for all relative links when navigateTo()
|
|
||||||
*/
|
|
||||||
function initScenarioAdapter(jstestdriver, initScenarioAndRun, config) {
|
|
||||||
if (jstestdriver) {
|
|
||||||
// create and register ScenarioPlugin
|
|
||||||
jstestdriver.pluginRegistrar.register(plugin);
|
|
||||||
plugin.runScenario = initScenarioAndRun;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HACK (angular.scenario.Application.navigateTo)
|
|
||||||
*
|
|
||||||
* We need to navigate to relative urls when running from browser (without JSTD),
|
|
||||||
* because we want to allow running scenario tests without creating its own virtual host.
|
|
||||||
* For example: http://angular.local/build/docs/docs-scenario.html
|
|
||||||
*
|
|
||||||
* On the other hand, when running with JSTD, we need to navigate to absolute urls,
|
|
||||||
* because of JSTD proxy. (proxy, because of same domain policy)
|
|
||||||
*
|
|
||||||
* So this hack is applied only if running with JSTD and change all relative urls to absolute.
|
|
||||||
*/
|
|
||||||
var appProto = angular.scenario.Application.prototype,
|
|
||||||
navigateTo = appProto.navigateTo,
|
|
||||||
relativeUrlPrefix = config && config.relativeUrlPrefix || '/';
|
|
||||||
|
|
||||||
appProto.navigateTo = function(url, loadFn, errorFn) {
|
|
||||||
if (url.charAt(0) != '/' && url.charAt(0) != '#' &&
|
|
||||||
url != 'about:blank' && !url.match(/^https?/)) {
|
|
||||||
url = relativeUrlPrefix + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
return navigateTo.call(this, url, loadFn, errorFn);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds proper TestResult object from given model spec
|
|
||||||
*
|
|
||||||
* TODO(vojta) report error details
|
|
||||||
*
|
|
||||||
* @param {angular.scenario.ObjectModel.Spec} spec
|
|
||||||
* @returns {jstestdriver.TestResult}
|
|
||||||
*/
|
|
||||||
function createTestResultFromSpec(spec) {
|
|
||||||
var map = {
|
|
||||||
success: 'PASSED',
|
|
||||||
error: 'ERROR',
|
|
||||||
failure: 'FAILED'
|
|
||||||
};
|
|
||||||
|
|
||||||
return new jstestdriver.TestResult(
|
|
||||||
spec.fullDefinitionName,
|
|
||||||
spec.name,
|
|
||||||
jstestdriver.TestResult.RESULT[map[spec.status]],
|
|
||||||
spec.error || '',
|
|
||||||
spec.line || '',
|
|
||||||
spec.duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates JSTD output (jstestdriver.TestResult)
|
|
||||||
*/
|
|
||||||
angular.scenario.output('jstd', function(context, runner, model) {
|
|
||||||
model.on('SpecEnd', function(spec) {
|
|
||||||
plugin.reportResult(createTestResultFromSpec(spec));
|
|
||||||
});
|
|
||||||
|
|
||||||
model.on('RunnerEnd', function() {
|
|
||||||
plugin.reportEnd();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
initScenarioAdapter(window.jstestdriver, angular.scenario.setUpAndRun, window.jstdScenarioAdapter);
|
|
||||||
})(window);
|
|
|
@ -1 +0,0 @@
|
||||||
{"full":"1.0.7","major":"1","minor":"0","dot":"7","codename":"monochromatic-rainbow","cdn":"1.0.6"}
|
|
|
@ -1 +0,0 @@
|
||||||
1.0.7
|
|
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 12 KiB |
|
@ -1,109 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
<aside class="span3" data-ng-include data-src="'partials/application-menu.html'"></aside>
|
|
||||||
<div id="actions-bg"></div>
|
|
||||||
|
|
||||||
<div id="container-right" class="span9">
|
|
||||||
<h1 data-ng-show="create"><span class="gray">New Application</span></h1>
|
|
||||||
|
|
||||||
<h1 data-ng-hide="create">
|
|
||||||
<span class="gray">{{application.name}}</span> configuration
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div data-ng-show="applicationForm.showErrors && applicationForm.$error.required" class="alert alert-error">
|
|
||||||
Please fill in all required fields
|
|
||||||
</div>
|
|
||||||
<p class="subtitle subtitle-right"><span class="required">*</span> Required fields</p>
|
|
||||||
|
|
||||||
<form class="form-horizontal" name="applicationForm" novalidate>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Settings</legend>
|
|
||||||
|
|
||||||
<div data-kc-input>
|
|
||||||
<label>Name</label>
|
|
||||||
<input class="input-xlarge" type="text" name="name" data-ng-model="application.name" autofocus
|
|
||||||
required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-kc-input>
|
|
||||||
<label>Enabled</label>
|
|
||||||
<input class="input-xlarge" type="checkbox" name="enabled" data-ng-model="application.enabled">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="realm">Realm <span class="required">*</span></label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<select data-ng-model="application.realm" id="realm" name="realm" data-ng-required>
|
|
||||||
<option data-ng-repeat="r in realms" value="{{r.id}}"
|
|
||||||
data-ng-selected="r.id == application.realm">{{r.name}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Roles</legend>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Roles</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<span class="label" style="margin-right: 1em;"
|
|
||||||
data-ng-repeat="r in (application.roles|orderBy:'toString()')">{{r}} <button
|
|
||||||
data-ng-click="removeRole(r)"><i class="icon-remove icon-white"></i></button></span>
|
|
||||||
|
|
||||||
<div class="input-append">
|
|
||||||
<input class="input-small" type="text" data-ng-model="newRole" placeHolder="Role"
|
|
||||||
data-kc-enter="addRole()"/>
|
|
||||||
<button class="btn" type="button" data-ng-click="addRole()">Add</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Initial Roles</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<span class="label" style="margin-right: 1em;"
|
|
||||||
data-ng-repeat="r in (application.initialRoles|orderBy:'toString()')">{{r}} <button
|
|
||||||
data-ng-click="removeInitialRole(r)"><i class="icon-remove icon-white"></i></button></span>
|
|
||||||
|
|
||||||
<div class="input-append">
|
|
||||||
<select style="width: auto;" data-ng-model="newInitialRole"
|
|
||||||
data-ng-click="addInitialRole()">
|
|
||||||
<option data-ng-repeat="r in (application.roles|remove:application.initialRoles|orderBy:'toString()')"
|
|
||||||
value="{{r}}">{{r}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div class="form-actions" data-ng-show="create">
|
|
||||||
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
|
|
||||||
</button>
|
|
||||||
<button type="submit" data-ng-click="cancel()" class="btn" data-ng-click="cancel()"
|
|
||||||
data-ng-show="changed">Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions" data-ng-show="!create">
|
|
||||||
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
|
|
||||||
changes
|
|
||||||
</button>
|
|
||||||
<button type="submit" data-ng-click="reset()" class="btn" data-ng-show="changed">Clear changes
|
|
||||||
</button>
|
|
||||||
<a href="#/applications" data-ng-hide="changed">View applications »</a>
|
|
||||||
<button type="submit" data-ng-click="remove()" class="btn btn-danger" data-ng-hide="changed">
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="container-right-bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,26 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
<aside class="span3" data-ng-include data-src="'partials/application-menu.html'"></aside>
|
|
||||||
<div id="actions-bg"></div>
|
|
||||||
|
|
||||||
<div id="container-right" class="span9">
|
|
||||||
<a class="btn btn-small pull-right" href="#/create/application">Add Application</a>
|
|
||||||
|
|
||||||
<h1>
|
|
||||||
<span class="gray">Applications</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Application</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr data-ng-repeat="application in applications">
|
|
||||||
<td><a href="#/applications/{{application.id}}">{{application.name}}</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div id="container-right-bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,20 +0,0 @@
|
||||||
<nav id="local-nav" data-ng-controller="ApplicationListCtrl">
|
|
||||||
<ul class="nav nav-list">
|
|
||||||
<li>
|
|
||||||
<div>
|
|
||||||
<span class="toggle">Applications</span>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li data-ng-repeat="a in applications" data-ng-class="path[1] == a.id && 'active'">
|
|
||||||
<a href="#/applications/{{a.id}}">{{a.name}}</a>
|
|
||||||
<ul class="sub-items" data-ng-show="path[1] == a.id">
|
|
||||||
<li data-ng-class="!path[2] && 'active'"><a href="#/applications/{{a.id}}">Configuration</a>
|
|
||||||
</li>
|
|
||||||
<li data-ng-class="path[2] == 'roles' && 'active'"><a href="#/applications/{{a.id}}/roles">Role
|
|
||||||
mapping</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,30 +0,0 @@
|
||||||
<header class="navbar navbar-fixed-top">
|
|
||||||
<div class="navbar-inner">
|
|
||||||
<div class="container">
|
|
||||||
<div class="nav-collapse">
|
|
||||||
<nav id="global-nav">
|
|
||||||
<ul class="nav">
|
|
||||||
<li class="divider-vertical-left" data-ng-class="path[0] == '' && 'active'"><a href="#">Home</a>
|
|
||||||
</li>
|
|
||||||
<li class="divider-vertical-left" data-ng-class="path[0] == 'applications' && 'active'"
|
|
||||||
data-ng-show="auth.loggedIn"><a href="#/applications">Applications</a></li>
|
|
||||||
<li class="divider-vertical-left" data-ng-class="path[0] == 'realms' && 'active'"
|
|
||||||
data-ng-show="auth.loggedIn"><a href="#/realms">Realms</a></li>
|
|
||||||
</ul>
|
|
||||||
<ul class="nav pull-right" data-ng-hide="auth.loggedIn">
|
|
||||||
<li><a href="/ejs-identity/api/login/system">Login</a></li>
|
|
||||||
<li><a href="/ejs-identity/api/register/system">Register</a></li>
|
|
||||||
</ul>
|
|
||||||
<ul class="nav pull-right" data-ng-show="auth.loggedIn">
|
|
||||||
<li class="dropdown"><a data-toggle="dropdown" class="dropdown-toggle" href="#"><i
|
|
||||||
class="icon-user icon-gray"></i> {{auth.user.displayName}} <i class="caret"></i></a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="" data-ng-click="auth.logout()">Sign Out</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
|
@ -1,40 +0,0 @@
|
||||||
<p>
|
|
||||||
Open <a href="https://code.google.com/apis/console/" target="_blank">https://code.google.com/apis/console/</a>. From
|
|
||||||
the
|
|
||||||
drop-down menu select <i>Create</i>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Use any name that you'd like, click <i>Create Project</i>, select <i>API Access</i> and click on <i>Create an OAuth
|
|
||||||
2.0 client ID</i>.</p>
|
|
||||||
|
|
||||||
<p>Use any product name you'd like and leave the other fields empty, then click <i>Next</i>. On the next page select <i>Web
|
|
||||||
application</i>
|
|
||||||
as the application type. Click <i>more options</i> next to <i>Your site or hostname</i>. Fill in the form with the
|
|
||||||
following values:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><b>Authorized Redirect URIs:</b> {{callbackUrl}}</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>Click on <i>Create client ID</i>. Insert <i>Client ID</i> and <i>Client secret</i> in the form below.</p>
|
|
||||||
|
|
||||||
<form class="form-horizontal" name="googleHelpForm">
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="providerHelp.key">Client ID </label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" class="input-xlarge" id="providerHelp.key"
|
|
||||||
data-ng-model="application.providers[providerHelp.index].key">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="providerHelp.secret">Client secret </label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" class="input-xlarge" id="providerHelp.secret"
|
|
||||||
data-ng-model="application.providers[providerHelp.index].secret">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p>Close the help panel and click <i>save changes</i>.</p>
|
|
|
@ -1,46 +0,0 @@
|
||||||
<p>
|
|
||||||
Open <a href="https://dev.twitter.com/apps" target="_blank">https://dev.twitter.com/apps</a>. Click on <i>Create a
|
|
||||||
new
|
|
||||||
application</i>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>Fill in name, description and website. For <i>Callback URL</i> use the following value:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li><b>Callback URL:</b> {{callbackUrl}}</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>Note: Twitter doesn't allow <b>localhost</b> as domain, use <b>127.0.0.1</b> instead!</p>
|
|
||||||
|
|
||||||
<p>Agree to the rules, fill in the captcha and click on <i>Create your Twitter application</i></p>
|
|
||||||
|
|
||||||
<p>Insert <i>Consumer key</i> and <i>Consumer secret</i> in the form below.</p>
|
|
||||||
|
|
||||||
<form class="form-horizontal" name="googleHelpForm">
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="providerHelp.key">Consumer key </label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" class="input-xlarge" id="providerHelp.key"
|
|
||||||
data-ng-model="application.providers[providerHelp.index].key">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="providerHelp.secret">Consumer secret </label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" class="input-xlarge" id="providerHelp.secret"
|
|
||||||
data-ng-model="application.providers[providerHelp.index].secret">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Now click on <i>Settings</i> and tick the box <i>Allow this application to be used to Sign in with Twitter</i>, and
|
|
||||||
click on <i>Update
|
|
||||||
this Twitter application's settings</i>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Close the help panel and click <i>save changes</i>.
|
|
||||||
</p>
|
|
|
@ -1,124 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
<aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside>
|
|
||||||
<div id="actions-bg"></div>
|
|
||||||
|
|
||||||
<div id="container-right" class="span9">
|
|
||||||
<h1 data-ng-show="create"><span class="gray">New Realm</span></h1>
|
|
||||||
|
|
||||||
<h1 data-ng-hide="create">
|
|
||||||
<span class="gray">{{realm.name}}</span> configuration
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div data-ng-show="realmForm.showErrors && realmForm.$error.required" class="alert alert-error">Please fill
|
|
||||||
in all required fields
|
|
||||||
</div>
|
|
||||||
<p class="subtitle subtitle-right"><span class="required">*</span> Required fields</p>
|
|
||||||
|
|
||||||
<form class="form-horizontal" name="realmForm" novalidate>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Settings</legend>
|
|
||||||
|
|
||||||
<div data-kc-input>
|
|
||||||
<label>Name</label>
|
|
||||||
<input class="input-xlarge" type="text" name="name" data-ng-model="realm.name" autofocus
|
|
||||||
required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-kc-input>
|
|
||||||
<label>Enabled</label>
|
|
||||||
<input class="input-xlarge" type="checkbox" name="enabled" data-ng-model="realm.enabled">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-kc-input>
|
|
||||||
<label>Social login</label>
|
|
||||||
<input class="input-xlarge" type="checkbox" name="social" data-ng-model="realm.social">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div data-kc-input>
|
|
||||||
<label>User registration</label>
|
|
||||||
<input class="input-xlarge" type="checkbox" name="social"
|
|
||||||
data-ng-model="realm.userRegistration">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label for="realmForm-tokenExpiration" class="control-label">Token expiration</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input class="input-small" type="text" name="tokenExpiration"
|
|
||||||
data-ng-model="realm.tokenExpiration">
|
|
||||||
<select style="width: auto;" name="tokenExpirationUnit"
|
|
||||||
data-ng-model="realm.tokenExpirationUnit">
|
|
||||||
<option value="SECONDS" data-ng-selected="!realm.tokenExpirationUnit">Seconds</option>
|
|
||||||
<option value="MINUTES">Minutes</option>
|
|
||||||
<option value="HOURS">Hours</option>
|
|
||||||
<option value="DAYS">Days</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>Roles</legend>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Roles</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<span class="label" style="margin-right: 1em;"
|
|
||||||
data-ng-repeat="r in (realm.roles|orderBy:'toString()')">{{r}} <button
|
|
||||||
data-ng-click="removeRole(r)"><i class="icon-remove icon-white"></i></button></span>
|
|
||||||
|
|
||||||
<div class="input-append">
|
|
||||||
<input class="input-small" type="text" data-ng-model="newRole" placeHolder="Role"
|
|
||||||
data-kc-enter="addRole()"/>
|
|
||||||
<button class="btn" type="button" data-ng-click="addRole()">Add</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label">Initial Roles</label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<span class="label" style="margin-right: 1em;"
|
|
||||||
data-ng-repeat="r in (realm.initialRoles|orderBy:'toString()')">{{r}} <button
|
|
||||||
data-ng-click="removeInitialRole(r)"><i class="icon-remove icon-white"></i></button></span>
|
|
||||||
|
|
||||||
<div class="input-append">
|
|
||||||
<select style="width: auto;" data-ng-model="newInitialRole"
|
|
||||||
data-ng-click="addInitialRole()">
|
|
||||||
<option data-ng-repeat="r in (realm.roles|remove:realm.initialRoles|orderBy:'toString()')"
|
|
||||||
value="{{r}}">{{r}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div class="form-actions" data-ng-show="create">
|
|
||||||
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
|
|
||||||
</button>
|
|
||||||
<button type="submit" data-ng-click="cancel()" class="btn" data-ng-click="cancel()"
|
|
||||||
data-ng-show="changed">Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions" data-ng-show="!create">
|
|
||||||
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
|
|
||||||
changes
|
|
||||||
</button>
|
|
||||||
<button type="submit" data-ng-click="reset()" class="btn" data-ng-show="changed">Clear changes
|
|
||||||
</button>
|
|
||||||
<a href="#/realms" data-ng-hide="changed">View realms »</a>
|
|
||||||
<button type="submit" data-ng-click="remove()" class="btn btn-danger" data-ng-hide="changed">
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div id="container-right-bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,27 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
<aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside>
|
|
||||||
<div id="actions-bg"></div>
|
|
||||||
|
|
||||||
<div id="container-right" class="span9">
|
|
||||||
<a class="btn btn-small pull-right" href="#/create/realm">Add Realm</a>
|
|
||||||
|
|
||||||
<h1>
|
|
||||||
<span class="gray">Realms</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Realm</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr data-ng-repeat="r in realms">
|
|
||||||
<td><a href="#/realms/{{r.id}}">{{r.name}}</a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="container-right-bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,21 +0,0 @@
|
||||||
<nav id="local-nav" data-ng-controller="RealmListCtrl">
|
|
||||||
<ul class="nav nav-list">
|
|
||||||
<li>
|
|
||||||
<div>
|
|
||||||
<span class="toggle">Realms</span>
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li data-ng-repeat="r in realms" data-ng-class="path[1] == r.id && 'active'">
|
|
||||||
<a href=#/realms/{{r.id}}>{{r.name}}</a>
|
|
||||||
<ul class="sub-items" data-ng-show="path[1] == r.id">
|
|
||||||
<li data-ng-class="!path[2] && 'active'"><a href="#/realms/{{r.id}}">Configuration</a></li>
|
|
||||||
<li data-ng-class="path[2] == 'users' && 'active'"><a href="#/realms/{{r.id}}/users">Users</a>
|
|
||||||
</li>
|
|
||||||
<li data-ng-class="path[2] == 'roles' && 'active'"><a href="#/realms/{{r.id}}/roles">Role
|
|
||||||
mapping</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
|
@ -1,50 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
<aside class="span3" data-ng-include data-src="'partials/' + path[0].slice(0, -1) + '-menu.html'"></aside>
|
|
||||||
|
|
||||||
<div id="actions-bg"></div>
|
|
||||||
|
|
||||||
<div id="container-right" class="span9">
|
|
||||||
<h1>
|
|
||||||
<span class="gray" data-ng-hide="create">{{realm.name}}</span> role mapping
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<ul class="nav nav-tabs">
|
|
||||||
<li data-ng-class="path[3] == r && 'active'" data-ng-repeat="r in (realm.roles|orderBy:'toString()')"><a
|
|
||||||
href="#/{{path[0]}}/{{realm.id}}/roles/{{r}}">{{r}}</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div data-ng-show="role">
|
|
||||||
<select style="width: auto;" id="realm" name="realm" data-ng-model="newUser" data-ng-click="addUser(u)">
|
|
||||||
<option data-ng-repeat="u in (allUsers|remove:users:'userId')" value="{{u.userId}}">{{u.userId}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Firstname</th>
|
|
||||||
<th>Lastname</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr data-ng-repeat="user in users">
|
|
||||||
<td>{{user.userId}}</td>
|
|
||||||
<td>{{user.firstName}}</td>
|
|
||||||
<td>{{user.lastName}}</td>
|
|
||||||
<td>{{user.email}}</td>
|
|
||||||
<td>
|
|
||||||
<button data-ng-click="removeUser(user.userId)">
|
|
||||||
<i class="icon-remove"></i>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="container-right-bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,107 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
<aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside>
|
|
||||||
<div id="actions-bg"></div>
|
|
||||||
|
|
||||||
<div id="container-right" class="span9">
|
|
||||||
<h1 data-ng-show="create"><span class="gray">New User</span></h1>
|
|
||||||
|
|
||||||
<h1 data-ng-hide="create">
|
|
||||||
<span class="gray">{{user.userId}}</span> configuration
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div data-ng-show="userForm.showErrors && userForm.$error.required" class="alert alert-error">Please fill in
|
|
||||||
all required fields
|
|
||||||
</div>
|
|
||||||
<p class="subtitle subtitle-right"><span class="required">*</span> Required fields</p>
|
|
||||||
|
|
||||||
<form class="form-horizontal" name="userForm" novalidate>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Details</legend>
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="name">Username <span class="required">*</span></label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" class="input-xlarge" id="name" name="name" data-ng-model="user.userId"
|
|
||||||
autofocus required data-ng-readonly="!create">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="email">Email </label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="email" class="input-xlarge" id="email" name="email" data-ng-model="user.email">
|
|
||||||
<span class="help-inline error"
|
|
||||||
data-ng-show="userForm.showErrors && userForm.email.$invalid">Invalid email</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="firstName">Firstname </label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" class="input-xlarge" id="firstName" data-ng-model="user.firstName">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="lastName">Lastname </label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="text" class="input-xlarge" id="lastName" data-ng-model="user.lastName">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="control-group">
|
|
||||||
<label class="control-label" for="password">Password <span class="required">*</span></label>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<input type="password" class="input-xlarge" id="password" name="password"
|
|
||||||
data-ng-model="user.password" data-ng-required="create">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset data-ng-show="user.attributes.length > 0">
|
|
||||||
<legend>Attributes</legend>
|
|
||||||
|
|
||||||
<table class="table table-striped table-bordered margin-top">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr data-ng-repeat="attribute in user.attributes">
|
|
||||||
<td><input type="text" placeholder="Name" value="{{attribute.name}}" readonly></td>
|
|
||||||
<td><input type="text" placeholder="Value" value="{{attribute.value}}" readonly></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div class="form-actions" data-ng-show="create">
|
|
||||||
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
|
|
||||||
</button>
|
|
||||||
<button type="submit" data-ng-click="cancel()" class="btn" data-ng-click="cancel()"
|
|
||||||
data-ng-show="changed">Cancel
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions" data-ng-show="!create">
|
|
||||||
<button type="submit" data-ng-click="save()" class="btn btn-primary" data-ng-show="changed">Save
|
|
||||||
changes
|
|
||||||
</button>
|
|
||||||
<button type="submit" data-ng-click="reset()" class="btn" data-ng-show="changed">Clear changes
|
|
||||||
</button>
|
|
||||||
<a href="#/realms/{{realm.id}}/users" data-ng-hide="changed">View users »</a>
|
|
||||||
<button type="submit" data-ng-click="remove()" class="btn btn-danger" data-ng-hide="changed">
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div id="container-right-bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,32 +0,0 @@
|
||||||
<div id="wrapper" class="container">
|
|
||||||
<div class="row">
|
|
||||||
<aside class="span3" data-ng-include data-src="'partials/realm-menu.html'"></aside>
|
|
||||||
<div id="actions-bg"></div>
|
|
||||||
|
|
||||||
<div id="container-right" class="span9">
|
|
||||||
<a class="btn btn-small pull-right" href="#/create/user/{{realm.id}}">Add User</a>
|
|
||||||
|
|
||||||
<h1>
|
|
||||||
<span class="gray">{{realm.name}}</span> users
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Username</th>
|
|
||||||
<th>Firstname</th>
|
|
||||||
<th>Lastname</th>
|
|
||||||
<th>Email</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tr data-ng-repeat="user in users">
|
|
||||||
<td><a href="#/realms/{{realm.id}}/users/{{user.userId}}">{{user.userId}}</a></td>
|
|
||||||
<td>{{user.firstName}}</td>
|
|
||||||
<td>{{user.lastName}}</td>
|
|
||||||
<td>{{user.email}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div id="container-right-bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|