Roberto Sánchez
2014-01-08 702f30f4dc61c5ca3c4747dd41170631716a414f
#394 feature - Added toaster for non intrusive messages
5 files added
3 files modified
changed files
securis/src/main/resources/static/admin.html patch | view | blame | history
securis/src/main/resources/static/css/bootstrap-dialog.css patch | view | blame | history
securis/src/main/resources/static/css/toaster.css patch | view | blame | history
securis/src/main/resources/static/js/admin.js patch | view | blame | history
securis/src/main/resources/static/js/bootstrap-dialog.js patch | view | blame | history
securis/src/main/resources/static/js/catalogs.json patch | view | blame | history
securis/src/main/resources/static/js/commons.js patch | view | blame | history
securis/src/main/resources/static/js/toaster.js patch | view | blame | history
securis/src/main/resources/static/admin.html
....@@ -5,12 +5,14 @@
55 <base href="/">
66 <meta charset="utf-8">
77 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
8
-<title></title>
8
+<title>SeCuris</title>
99 <meta name="description" content="">
1010 <meta name="viewport" content="width=device-width">
1111
12
-<link rel="stylesheet"
13
- href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
12
+<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
13
+<link rel="stylesheet" href="/css/bootstrap-dialog.css">
14
+<link rel="stylesheet" href="/css/toaster.css">
15
+
1416 <style>
1517 body {
1618 padding-top: 50px;
....@@ -103,8 +105,6 @@
103105 <ul class="nav navbar-nav">
104106 <li><a ng-click="editNew()"><span class="glyphicon glyphicon-plus"></span>
105107 New</a></li>
106
- <li><a ng-click="edit()"><span class="glyphicon glyphicon-pencil"></span>
107
- Edit</a></li>
108108 <li><a ng-click="cancel()"> <span
109109 class="glyphicon glyphicon-ban-circle"></span> Cancel
110110 </a></li>
....@@ -164,11 +164,14 @@
164164 </tr>
165165 </thead>
166166 <tbody>
167
- <tr ng-repeat="row in list | filter:searchText">
168
- <td ng-repeat="field in catalogMetadata.list_fields" ng-bind="row[field] "></td>
167
+ <tr ng-repeat="row in list | filter:searchText" ng-dblclick="edit(row)">
168
+ <td ng-repeat="field in catalogMetadata.list_fields" ng-bind="print(field, row[field])"></td>
169169
170
- <td><span ng-click="editRow()"
171
- class="glyphicon glyphicon-pencil"></span></td>
170
+ <td><span ng-click="edit(row)"
171
+ class="glyphicon glyphicon-pencil"></span>
172
+ <span ng-click="delete(row)"
173
+ class="glyphicon glyphicon-remove"></span>
174
+ </td>
172175 </tr>
173176 </tbody>
174177 <tfoot>
....@@ -199,6 +202,12 @@
199202 src="/js/angular-resource.min.js"></script>
200203 <script type="text/javascript"
201204 src="/js/angular-animate.min.js"></script>
205
+ <script type="text/javascript"
206
+ src="/js/bootstrap-dialog.js"></script>
207
+ <script type="text/javascript"
208
+ src="/js/toaster.js"></script>
209
+
210
+
202211 <!--
203212 <script
204213 src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
....@@ -222,5 +231,7 @@
222231 });
223232
224233 </script>
234
+
235
+ <toaster-container toaster-options="{'time-out': 3000}"></toaster-container>
225236 </body>
226237 </html>
securis/src/main/resources/static/css/bootstrap-dialog.css
....@@ -0,0 +1,120 @@
1
+.bootstrap-dialog {
2
+
3
+}
4
+.bootstrap-dialog .modal-header {
5
+ border-top-left-radius: 4px;
6
+ border-top-right-radius: 4px;
7
+}
8
+.bootstrap-dialog .bootstrap-dialog-title {
9
+ color: #fff;
10
+ display: inline-block;
11
+}
12
+.bootstrap-dialog.type-default .bootstrap-dialog-title {
13
+ color: #333;
14
+}
15
+.bootstrap-dialog.size-normal .bootstrap-dialog-title {
16
+ font-size: 16px;
17
+}
18
+.bootstrap-dialog.size-large .bootstrap-dialog-title {
19
+ font-size: 24px;
20
+}
21
+.bootstrap-dialog .bootstrap-dialog-close-button {
22
+ float: right;
23
+ filter:alpha(opacity=90);
24
+ -moz-opacity:0.9;
25
+ -khtml-opacity: 0.9;
26
+ opacity: 0.9;
27
+}
28
+.bootstrap-dialog.size-normal .bootstrap-dialog-close-button {
29
+ font-size: 20px;
30
+}
31
+.bootstrap-dialog.size-large .bootstrap-dialog-close-button {
32
+ font-size: 30px;
33
+}
34
+.bootstrap-dialog .bootstrap-dialog-close-button:hover {
35
+ cursor: pointer;
36
+ filter: alpha(opacity=100);
37
+ -moz-opacity: 1;
38
+ -khtml-opacity: 1;
39
+ opacity: 1;
40
+}
41
+.bootstrap-dialog.size-normal .bootstrap-dialog-message {
42
+ font-size: 14px;
43
+}
44
+.bootstrap-dialog.size-large .bootstrap-dialog-message {
45
+ font-size: 18px;
46
+}
47
+.bootstrap-dialog.type-default .modal-header {
48
+ background-color: #fff;
49
+}
50
+.bootstrap-dialog.type-info .modal-header {
51
+ background-color: #5bc0de;
52
+}
53
+.bootstrap-dialog.type-primary .modal-header {
54
+ background-color: #428bca;
55
+}
56
+.bootstrap-dialog.type-success .modal-header {
57
+ background-color: #5cb85c;
58
+}
59
+.bootstrap-dialog.type-warning .modal-header {
60
+ background-color: #f0ad4e;
61
+}
62
+.bootstrap-dialog.type-danger .modal-header {
63
+ background-color: #d9534f;
64
+}
65
+.bootstrap-dialog .bootstrap-dialog-button-icon {
66
+ margin-right: 3px;
67
+}
68
+
69
+/**
70
+ * Icon animation
71
+ * Copied from font-awesome: http://fontawesome.io/
72
+ **/
73
+.icon-spin {
74
+ display: inline-block;
75
+ -moz-animation: spin 2s infinite linear;
76
+ -o-animation: spin 2s infinite linear;
77
+ -webkit-animation: spin 2s infinite linear;
78
+ animation: spin 2s infinite linear;
79
+}
80
+@-moz-keyframes spin {
81
+ 0% {
82
+ -moz-transform: rotate(0deg);
83
+}
84
+100% {
85
+ -moz-transform: rotate(359deg);
86
+}
87
+}
88
+@-webkit-keyframes spin {
89
+ 0% {
90
+ -webkit-transform: rotate(0deg);
91
+}
92
+100% {
93
+ -webkit-transform: rotate(359deg);
94
+}
95
+}
96
+@-o-keyframes spin {
97
+ 0% {
98
+ -o-transform: rotate(0deg);
99
+}
100
+100% {
101
+ -o-transform: rotate(359deg);
102
+}
103
+}
104
+@-ms-keyframes spin {
105
+ 0% {
106
+ -ms-transform: rotate(0deg);
107
+}
108
+100% {
109
+ -ms-transform: rotate(359deg);
110
+}
111
+}
112
+@keyframes spin {
113
+ 0% {
114
+ transform: rotate(0deg);
115
+}
116
+100% {
117
+ transform: rotate(359deg);
118
+}
119
+}
120
+/** End of icon animation **/
securis/src/main/resources/static/css/toaster.css
....@@ -0,0 +1,207 @@
1
+/*
2
+ * Toastr
3
+ * Version 2.0.1
4
+ * Copyright 2012 John Papa and Hans Fjällemark.
5
+ * All Rights Reserved.
6
+ * Use, reproduction, distribution, and modification of this code is subject to the terms and
7
+ * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
8
+ *
9
+ * Author: John Papa and Hans Fjällemark
10
+ * Project: https://github.com/CodeSeven/toastr
11
+ */
12
+.toast-title {
13
+ font-weight: bold;
14
+}
15
+.toast-message {
16
+ -ms-word-wrap: break-word;
17
+ word-wrap: break-word;
18
+}
19
+.toast-message a,
20
+.toast-message label {
21
+ color: #ffffff;
22
+}
23
+.toast-message a:hover {
24
+ color: #cccccc;
25
+ text-decoration: none;
26
+}
27
+
28
+.toast-close-button {
29
+ position: relative;
30
+ right: -0.3em;
31
+ top: -0.3em;
32
+ float: right;
33
+ font-size: 20px;
34
+ font-weight: bold;
35
+ color: #ffffff;
36
+ -webkit-text-shadow: 0 1px 0 #ffffff;
37
+ text-shadow: 0 1px 0 #ffffff;
38
+ opacity: 0.8;
39
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
40
+ filter: alpha(opacity=80);
41
+}
42
+.toast-close-button:hover,
43
+.toast-close-button:focus {
44
+ color: #000000;
45
+ text-decoration: none;
46
+ cursor: pointer;
47
+ opacity: 0.4;
48
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
49
+ filter: alpha(opacity=40);
50
+}
51
+
52
+/*Additional properties for button version
53
+ iOS requires the button element instead of an anchor tag.
54
+ If you want the anchor version, it requires `href="#"`.*/
55
+button.toast-close-button {
56
+ padding: 0;
57
+ cursor: pointer;
58
+ background: transparent;
59
+ border: 0;
60
+ -webkit-appearance: none;
61
+}
62
+.toast-top-full-width {
63
+ top: 0;
64
+ right: 0;
65
+ width: 100%;
66
+}
67
+.toast-bottom-full-width {
68
+ bottom: 0;
69
+ right: 0;
70
+ width: 100%;
71
+}
72
+.toast-top-left {
73
+ top: 12px;
74
+ left: 12px;
75
+}
76
+.toast-top-right {
77
+ top: 12px;
78
+ right: 12px;
79
+}
80
+.toast-bottom-right {
81
+ right: 12px;
82
+ bottom: 12px;
83
+}
84
+.toast-bottom-left {
85
+ bottom: 12px;
86
+ left: 12px;
87
+}
88
+#toast-container {
89
+ position: fixed;
90
+ z-index: 999999;
91
+ /*overrides*/
92
+
93
+}
94
+#toast-container * {
95
+ -moz-box-sizing: border-box;
96
+ -webkit-box-sizing: border-box;
97
+ box-sizing: border-box;
98
+}
99
+#toast-container > div {
100
+ margin: 0 0 6px;
101
+ padding: 15px 15px 15px 50px;
102
+ width: 300px;
103
+ -moz-border-radius: 3px 3px 3px 3px;
104
+ -webkit-border-radius: 3px 3px 3px 3px;
105
+ border-radius: 3px 3px 3px 3px;
106
+ background-position: 15px center;
107
+ background-repeat: no-repeat;
108
+ -moz-box-shadow: 0 0 12px #999999;
109
+ -webkit-box-shadow: 0 0 12px #999999;
110
+ box-shadow: 0 0 12px #999999;
111
+ color: #ffffff;
112
+ opacity: 0.8;
113
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
114
+ filter: alpha(opacity=80);
115
+}
116
+#toast-container > :hover {
117
+ -moz-box-shadow: 0 0 12px #000000;
118
+ -webkit-box-shadow: 0 0 12px #000000;
119
+ box-shadow: 0 0 12px #000000;
120
+ opacity: 1;
121
+ -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
122
+ filter: alpha(opacity=100);
123
+ cursor: pointer;
124
+}
125
+#toast-container > .toast-info {
126
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
127
+}
128
+#toast-container > .toast-error {
129
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
130
+}
131
+#toast-container > .toast-success {
132
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
133
+}
134
+#toast-container > .toast-warning {
135
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
136
+}
137
+#toast-container.toast-top-full-width > div,
138
+#toast-container.toast-bottom-full-width > div {
139
+ width: 96%;
140
+ margin: auto;
141
+}
142
+.toast {
143
+ background-color: #030303;
144
+}
145
+.toast-success {
146
+ background-color: #51a351;
147
+}
148
+.toast-error {
149
+ background-color: #bd362f;
150
+}
151
+.toast-info {
152
+ background-color: #2f96b4;
153
+}
154
+.toast-warning {
155
+ background-color: #f89406;
156
+}
157
+/*Responsive Design*/
158
+@media all and (max-width: 240px) {
159
+ #toast-container > div {
160
+ padding: 8px 8px 8px 50px;
161
+ width: 11em;
162
+ }
163
+ #toast-container .toast-close-button {
164
+ right: -0.2em;
165
+ top: -0.2em;
166
+}
167
+ }
168
+@media all and (min-width: 241px) and (max-width: 480px) {
169
+ #toast-container > div {
170
+ padding: 8px 8px 8px 50px;
171
+ width: 18em;
172
+ }
173
+ #toast-container .toast-close-button {
174
+ right: -0.2em;
175
+ top: -0.2em;
176
+}
177
+}
178
+@media all and (min-width: 481px) and (max-width: 768px) {
179
+ #toast-container > div {
180
+ padding: 15px 15px 15px 50px;
181
+ width: 25em;
182
+ }
183
+}
184
+
185
+ /*
186
+ * AngularJS-Toaster
187
+ * Version 0.3
188
+ */
189
+#toast-container > div.ng-enter,
190
+#toast-container > div.ng-leave
191
+{
192
+ -webkit-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
193
+ -moz-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
194
+ -ms-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
195
+ -o-transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
196
+ transition: 1000ms cubic-bezier(0.250, 0.250, 0.750, 0.750) all;
197
+}
198
+
199
+#toast-container > div.ng-enter.ng-enter-active,
200
+#toast-container > div.ng-leave {
201
+ opacity: 0.8;
202
+}
203
+
204
+#toast-container > div.ng-leave.ng-leave-active,
205
+#toast-container > div.ng-enter {
206
+ opacity: 0;
207
+}
securis/src/main/resources/static/js/admin.js
....@@ -1,7 +1,7 @@
11 (function() {
22 'use strict';
33
4
- var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource' ]);
4
+ var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource', 'toaster' ]);
55
66 app.directive(
77 'catalogField',
....@@ -22,7 +22,7 @@
2222 };
2323 });
2424
25
- app.factory('Catalogs', function($http, $resource) {
25
+ app.factory('Catalogs', function($http, $resource, toaster) {
2626 var CatalogsService = {
2727 resources : {
2828 application : $resource('/application/:appId', {
....@@ -68,7 +68,25 @@
6868 return CatalogsService.data ? CatalogsService.data[index] : {};
6969 },
7070 save: function(catalog, data) {
71
- console.log('save ???? ' );
71
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
72
+ function success(data) {
73
+ console.log('success')
74
+ console.log(data)
75
+ toaster.pop('success', "Data saved sucessfully in " + catalog);
76
+ }
77
+ function fail(data, status) {
78
+ var errorMsg = {500: 'Server error', 404: 'Item to modify was not found'}[data.status]
79
+ toaster.pop('error', "Error saving data in " + catalog, errorMsg);
80
+ console.log('error')
81
+ console.error(data)
82
+ console.error(status)
83
+ }
84
+ if (data.id && data.id !== '')
85
+ return resource.update(data, success, fail)
86
+ else
87
+ return resource.save(data, success, fail)
88
+ },
89
+ remove: function(catalog, data) {
7290 var resource = CatalogsService.resources[catalog.toLowerCase()];
7391 function success(data) {
7492 console.log('success')
....@@ -79,10 +97,7 @@
7997 console.error(data)
8098 console.error(status)
8199 }
82
- if (data.id && data.id !== '')
83
- return resource.update(data, success, fail)
84
- else
85
- return resource.save(data, success, fail)
100
+ return resource.remove({}, data, success, fail)
86101 },
87102 query: function(catalog, callback) {
88103 console.log('HI catalog ???? ' + catalog);
....@@ -108,38 +123,58 @@
108123 '$scope',
109124 '$http',
110125 'Catalogs',
111
- function($scope, $http, catalogs) {
126
+ function($scope, $http, Catalogs) {
112127 $scope.formu = {};
113128 $scope.catalogIndex = 0;
114
- $scope.catalogs = catalogs.list(function() {
115
- $scope.catalogMetadata = catalogs.getMetadata($scope.catalogIndex);
116
- $scope.list = catalogs.query(catalogs.getResource($scope.catalogIndex));
129
+ $scope.catalogs = Catalogs.list(function() {
130
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
131
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
117132 });
118133
119134 $scope.catalogMetadata = {};
120135 $scope.selectCatalog = function(index, $event) {
121136 $scope.catalogIndex = index;
122
- $scope.catalogMetadata = catalogs.getMetadata($scope.catalogIndex);
123
- $scope.list = catalogs.query(catalogs.getResource($scope.catalogIndex));
137
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
138
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
124139 console.log($event);
125140 }
126
- } ]);
127
-
128
- app.controller('CatalogFormCtrl', [ '$scope', '$http', 'Catalogs',
129
- function($scope, $http, Catalogs) {
130
- $scope.showForm = false;
131
- $scope.scope = $scope;
132
- console.log('Form: currentCatalog:' + $scope.cataLogIndex);
133
- $scope.editNew = function() {
141
+ $scope.edit = function(data) {
134142 $scope.showForm = true;
135
- $scope.isNew = true;
143
+ $scope.isNew = false;
144
+ for (var k in data) {
145
+ if (k.indexOf('$') !== 0) $scope.formu[k] = data[k]
146
+ }
147
+ // TODO: Load in formu values for Form
136148 // $scope.formu = {};
137149 }
138
- $scope.edit = function() {
139
- $scope.showForm = true;
150
+ $scope.delete = function(data) {
151
+ BootstrapDialog.confirm('The record will be deleted, are you sure?', function(result){
152
+ if(result) {
153
+ var catalogName = Catalogs.getResource($scope.catalogIndex);
154
+ var promise = Catalogs.remove(catalogName, data).$promise;
155
+ promise.then(function(data) {
156
+ $scope.list = Catalogs.query(catalogName);
157
+ });
158
+ }
159
+ });
160
+ $scope.showForm = false;
140161 $scope.isNew = false;
141162 // TODO: Load in formu values for Form
142163 // $scope.formu = {};
164
+ }
165
+
166
+ } ]);
167
+
168
+ app.controller('CatalogFormCtrl', [ '$scope', '$http', 'toaster', 'Catalogs',
169
+ function($scope, $http, toaster, Catalogs) {
170
+ $scope.showForm = false;
171
+ $scope.scope = $scope;
172
+ console.log('Form: currentCatalog:' + $scope.cataLogIndex);
173
+
174
+ $scope.editNew = function() {
175
+ $scope.showForm = true;
176
+ $scope.isNew = true;
177
+ $scope.formu = {};
143178 }
144179 $scope.cancel = function() {
145180 $scope.showForm = false;
....@@ -151,34 +186,44 @@
151186 } else {
152187 var catalogName = Catalogs.getResource($scope.catalogIndex);
153188 var promise = Catalogs.save(catalogName, $scope.formu).$promise;
154
- console.log('================================================================================================================================')
155
- console.log(promise)
156
- promise.then(function(data) {
157
- console.log('Command returned OK form promise')
158
- console.log(data)
189
+ promise.then(function(data, otro) {
190
+ if ($scope.isNew) {
191
+ $scope.formu = {}
192
+ $('#name').focus();
193
+ } else {
194
+ $scope.cancel();
195
+ }
196
+ // $scope.formu = {};
159197 $scope.$parent.list = Catalogs.query(catalogName);
160
-
198
+ }, function(error, otro) {
199
+ console.log('then error');
200
+ console.log(error);
201
+ console.log(otro);
161202 });
203
+
162204 }
163205 }
164206 } ]);
165207
166
- app.controller('CatalogListCtrl', [ '$scope', '$http', 'Catalogs',
167
- function($scope, $http, Catalogs) {
208
+ app.controller('CatalogListCtrl', [ '$scope', '$http', '$filter', 'Catalogs',
209
+ function($scope, $http, $filter, Catalogs) {
168210 console.log('List: currentCatalog: ' + $scope.currentCatalog);
169
- $scope.myFilter = function(field) {
170
- if (field === 'creationTimestamp')
171
- return 'date';
172
- else '';
211
+ var _indexOfField = function(name) {
212
+ if (!$scope.catalogMetadata) return -1;
213
+ for (var i = $scope.catalogMetadata.fields.length - 1; i >= 0 && $scope.catalogMetadata.fields[i].name !== name; i--);
214
+ return i;
215
+ }
216
+
217
+ $scope.print = function(name, value) {
218
+ var index = _indexOfField(name);
219
+ if (index === -1) return value;
220
+ var type = $scope.catalogMetadata.fields[index].type;
221
+
222
+ return type === 'date' ? $filter('date')(value, 'yyyy-MM-dd') : value;
173223 }
174224
175225 $scope.display = function(name) {
176
- var _indexOf = function(name) {
177
- if (!$scope.catalogMetadata) return -1;
178
- for (var i = $scope.catalogMetadata.fields.length - 1; i >= 0 && $scope.catalogMetadata.fields[i].name !== name; i--);
179
- return i;
180
- }
181
- var index = _indexOf(name);
226
+ var index = _indexOfField(name);
182227 return index === -1 ? '' : $scope.catalogMetadata.fields[index].display;
183228 }
184229
securis/src/main/resources/static/js/bootstrap-dialog.js
....@@ -0,0 +1,654 @@
1
+/* ================================================
2
+ * Make use of Twitter Bootstrap's modal more monkey-friendly.
3
+ *
4
+ * For Bootstrap 3.
5
+ *
6
+ * javanoob@hotmail.com
7
+ *
8
+ * Licensed under The MIT License.
9
+ * ================================================ */
10
+var BootstrapDialog = null;
11
+!function($) {
12
+ "use strict";
13
+
14
+ BootstrapDialog = function(options) {
15
+ this.defaultOptions = {
16
+ id: BootstrapDialog.newGuid(),
17
+ type: BootstrapDialog.TYPE_PRIMARY,
18
+ size: BootstrapDialog.SIZE_NORMAL,
19
+ cssClass: '',
20
+ title: null,
21
+ message: null,
22
+ buttons: [],
23
+ closable: true,
24
+ spinicon: BootstrapDialog.ICON_SPINNER,
25
+ data: {},
26
+ onshow: null,
27
+ onhide: null,
28
+ autodestroy: true
29
+ };
30
+ this.indexedButtons = {};
31
+ this.realized = false;
32
+ this.opened = false;
33
+ this.initOptions(options);
34
+ this.holdThisInstance();
35
+ };
36
+
37
+ /**
38
+ * Some constants.
39
+ */
40
+ BootstrapDialog.NAMESPACE = 'bootstrap-dialog';
41
+
42
+ BootstrapDialog.TYPE_DEFAULT = 'type-default';
43
+ BootstrapDialog.TYPE_INFO = 'type-info';
44
+ BootstrapDialog.TYPE_PRIMARY = 'type-primary';
45
+ BootstrapDialog.TYPE_SUCCESS = 'type-success';
46
+ BootstrapDialog.TYPE_WARNING = 'type-warning';
47
+ BootstrapDialog.TYPE_DANGER = 'type-danger';
48
+
49
+ BootstrapDialog.DEFAULT_TEXTS = {};
50
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DEFAULT] = 'Information';
51
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_INFO] = 'Information';
52
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_PRIMARY] = 'Information';
53
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_SUCCESS] = 'Success';
54
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_WARNING] = 'Warning';
55
+ BootstrapDialog.DEFAULT_TEXTS[BootstrapDialog.TYPE_DANGER] = 'Danger';
56
+
57
+ BootstrapDialog.SIZE_NORMAL = 'size-normal';
58
+ BootstrapDialog.SIZE_LARGE = 'size-large';
59
+
60
+ BootstrapDialog.BUTTON_SIZES = {};
61
+ BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_NORMAL] = '';
62
+ BootstrapDialog.BUTTON_SIZES[BootstrapDialog.SIZE_LARGE] = 'btn-lg';
63
+
64
+ BootstrapDialog.ICON_SPINNER = 'glyphicon glyphicon-asterisk';
65
+
66
+ /**
67
+ * Open / Close all created dialogs all at once.
68
+ */
69
+ BootstrapDialog.dialogs = {};
70
+ BootstrapDialog.openAll = function() {
71
+ $.each(BootstrapDialog.dialogs, function(id, dialogInstance) {
72
+ dialogInstance.open();
73
+ });
74
+ };
75
+ BootstrapDialog.closeAll = function() {
76
+ $.each(BootstrapDialog.dialogs, function(id, dialogInstance) {
77
+ dialogInstance.close();
78
+ });
79
+ };
80
+
81
+ BootstrapDialog.prototype = {
82
+ constructor: BootstrapDialog,
83
+ initOptions: function(options) {
84
+ this.options = $.extend(true, this.defaultOptions, options);
85
+
86
+ return this;
87
+ },
88
+ holdThisInstance: function() {
89
+ BootstrapDialog.dialogs[this.getId()] = this;
90
+
91
+ return this;
92
+ },
93
+ initModalStuff: function() {
94
+ this.setModal(this.createModal())
95
+ .setModalDialog(this.createModalDialog())
96
+ .setModalContent(this.createModalContent())
97
+ .setModalHeader(this.createModalHeader())
98
+ .setModalBody(this.createModalBody())
99
+ .setModalFooter(this.createModalFooter());
100
+
101
+ this.getModal().append(this.getModalDialog());
102
+ this.getModalDialog().append(this.getModalContent());
103
+ this.getModalContent()
104
+ .append(this.getModalHeader())
105
+ .append(this.getModalBody())
106
+ .append(this.getModalFooter());
107
+
108
+ return this;
109
+ },
110
+ createModal: function() {
111
+ return $('<div class="modal fade" tabindex="-1" id="' + this.getId() + '"></div>');
112
+ },
113
+ getModal: function() {
114
+ return this.$modal;
115
+ },
116
+ setModal: function($modal) {
117
+ this.$modal = $modal;
118
+
119
+ return this;
120
+ },
121
+ createModalDialog: function() {
122
+ return $('<div class="modal-dialog"></div>');
123
+ },
124
+ getModalDialog: function() {
125
+ return this.$modalDialog;
126
+ },
127
+ setModalDialog: function($modalDialog) {
128
+ this.$modalDialog = $modalDialog;
129
+
130
+ return this;
131
+ },
132
+ createModalContent: function() {
133
+ return $('<div class="modal-content"></div>');
134
+ },
135
+ getModalContent: function() {
136
+ return this.$modalContent;
137
+ },
138
+ setModalContent: function($modalContent) {
139
+ this.$modalContent = $modalContent;
140
+
141
+ return this;
142
+ },
143
+ createModalHeader: function() {
144
+ return $('<div class="modal-header"></div>');
145
+ },
146
+ getModalHeader: function() {
147
+ return this.$modalHeader;
148
+ },
149
+ setModalHeader: function($modalHeader) {
150
+ this.$modalHeader = $modalHeader;
151
+
152
+ return this;
153
+ },
154
+ createModalBody: function() {
155
+ return $('<div class="modal-body"></div>');
156
+ },
157
+ getModalBody: function() {
158
+ return this.$modalBody;
159
+ },
160
+ setModalBody: function($modalBody) {
161
+ this.$modalBody = $modalBody;
162
+
163
+ return this;
164
+ },
165
+ createModalFooter: function() {
166
+ return $('<div class="modal-footer"></div>');
167
+ },
168
+ getModalFooter: function() {
169
+ return this.$modaFooter;
170
+ },
171
+ setModalFooter: function($modaFooter) {
172
+ this.$modaFooter = $modaFooter;
173
+
174
+ return this;
175
+ },
176
+ createDynamicContent: function(rawContent) {
177
+ var content = null;
178
+ if (typeof rawContent === 'function') {
179
+ content = rawContent.call(rawContent, this);
180
+ } else {
181
+ content = rawContent;
182
+ }
183
+ if (typeof content === 'string') {
184
+ content = this.formatStringContent(content);
185
+ }
186
+
187
+ return content;
188
+ },
189
+ formatStringContent: function(content) {
190
+ return content.replace(/\r\n/g, '<br />').replace(/[\r\n]/g, '<br />');
191
+ },
192
+ setData: function(key, value) {
193
+ this.options.data[key] = value;
194
+
195
+ return this;
196
+ },
197
+ getData: function(key) {
198
+ return this.options.data[key];
199
+ },
200
+ setId: function(id) {
201
+ this.options.id = id;
202
+
203
+ return this;
204
+ },
205
+ getId: function() {
206
+ return this.options.id;
207
+ },
208
+ getType: function() {
209
+ return this.options.type;
210
+ },
211
+ setType: function(type) {
212
+ this.options.type = type;
213
+
214
+ return this;
215
+ },
216
+ getSize: function() {
217
+ return this.options.size;
218
+ },
219
+ setSize: function(size) {
220
+ this.options.size = size;
221
+
222
+ return this;
223
+ },
224
+ getCssClass: function() {
225
+ return this.options.cssClass;
226
+ },
227
+ setCssClass: function(cssClass){
228
+ this.options.cssClass = cssClass;
229
+
230
+ return this;
231
+ },
232
+ getTitle: function() {
233
+ return this.options.title;
234
+ },
235
+ setTitle: function(title) {
236
+ this.options.title = title;
237
+
238
+ return this;
239
+ },
240
+ getMessage: function() {
241
+ return this.options.message;
242
+ },
243
+ setMessage: function(message) {
244
+ this.options.message = message;
245
+
246
+ return this;
247
+ },
248
+ isClosable: function() {
249
+ return this.options.closable;
250
+ },
251
+ setClosable: function(closable) {
252
+ this.options.closable = closable;
253
+ this.updateClosable();
254
+
255
+ return this;
256
+ },
257
+ getSpinicon: function() {
258
+ return this.options.spinicon;
259
+ },
260
+ setSpinicon: function(spinicon) {
261
+ this.options.spinicon = spinicon;
262
+
263
+ return this;
264
+ },
265
+ addButton: function(button) {
266
+ this.options.buttons.push(button);
267
+
268
+ return this;
269
+ },
270
+ addButtons: function(buttons) {
271
+ var that = this;
272
+
273
+ $.each(buttons, function(index, button) {
274
+ that.addButton(button);
275
+ });
276
+
277
+ return this;
278
+ },
279
+ getButtons: function() {
280
+ return this.options.buttons;
281
+ },
282
+ setButtons: function(buttons) {
283
+ this.options.buttons = buttons;
284
+
285
+ return this;
286
+ },
287
+ /**
288
+ * If there is id provided for a button option, it will be in dialog.indexedButtons list.
289
+ *
290
+ * In that case you can use dialog.getButton(id) to find the button.
291
+ *
292
+ * @param {type} id
293
+ * @returns {undefined}
294
+ */
295
+ getButton: function(id) {
296
+ if (typeof this.indexedButtons[id] !== 'undefined') {
297
+ return this.indexedButtons[id];
298
+ }
299
+
300
+ return null;
301
+ },
302
+ getButtonSize: function() {
303
+ if (typeof BootstrapDialog.BUTTON_SIZES[this.getSize()] !== 'undefined') {
304
+ return BootstrapDialog.BUTTON_SIZES[this.getSize()];
305
+ }
306
+
307
+ return '';
308
+ },
309
+ isAutodestroy: function() {
310
+ return this.options.autodestroy;
311
+ },
312
+ setAutodestroy: function(autodestroy) {
313
+ this.options.autodestroy = autodestroy;
314
+ },
315
+ getDefaultText: function() {
316
+ return BootstrapDialog.DEFAULT_TEXTS[this.getType()];
317
+ },
318
+ getNamespace: function(name) {
319
+ return BootstrapDialog.NAMESPACE + '-' + name;
320
+ },
321
+ createHeaderContent: function() {
322
+ var $container = $('<div></div>');
323
+ $container.addClass(this.getNamespace('header'));
324
+
325
+ // title
326
+ $container.append(this.createTitleContent());
327
+
328
+ // Close button
329
+ $container.append(this.createCloseButton());
330
+
331
+ return $container;
332
+ },
333
+ createTitleContent: function() {
334
+ var $title = $('<div></div>');
335
+ $title.addClass(this.getNamespace('title'));
336
+ $title.append(this.getTitle() !== null ? this.createDynamicContent(this.getTitle()) : this.getDefaultText());
337
+
338
+ return $title;
339
+ },
340
+ createCloseButton: function() {
341
+ var $container = $('<div></div>');
342
+ $container.addClass(this.getNamespace('close-button'));
343
+ var $icon = $('<button class="close">×</button>');
344
+ $container.append($icon);
345
+ $container.on('click', {dialog: this}, function(event) {
346
+ event.data.dialog.close();
347
+ });
348
+
349
+ return $container;
350
+ },
351
+ createBodyContent: function() {
352
+ var $container = $('<div></div>');
353
+ $container.addClass(this.getNamespace('body'));
354
+
355
+ // Message
356
+ $container.append(this.createMessageContent());
357
+
358
+ return $container;
359
+ },
360
+ createMessageContent: function() {
361
+ var $message = $('<div></div>');
362
+ $message.addClass(this.getNamespace('message'));
363
+ $message.append(this.createDynamicContent(this.getMessage()));
364
+
365
+ return $message;
366
+ },
367
+ createFooterContent: function() {
368
+ var $container = $('<div></div>');
369
+ $container.addClass(this.getNamespace('footer'));
370
+
371
+ // Buttons
372
+ $container.append(this.createFooterButtons());
373
+
374
+ return $container;
375
+ },
376
+ createFooterButtons: function() {
377
+ var that = this;
378
+ var $container = $('<div></div>');
379
+ $container.addClass(this.getNamespace('footer-buttons'));
380
+ this.indexedButtons = {};
381
+ $.each(this.options.buttons, function(index, button) {
382
+ var $button = that.createButton(button);
383
+ if (typeof button.id !== 'undefined') {
384
+ that.indexedButtons[button.id] = $button;
385
+ }
386
+ $container.append($button);
387
+ });
388
+
389
+ return $container;
390
+ },
391
+ createButton: function(button) {
392
+ var $button = $('<button class="btn"></button>');
393
+ $button.addClass(this.getButtonSize());
394
+
395
+ // Icon
396
+ if (typeof button.icon !== undefined && $.trim(button.icon) !== '') {
397
+ $button.append(this.createButtonIcon(button.icon));
398
+ }
399
+
400
+ // Label
401
+ if (typeof button.label !== undefined) {
402
+ $button.append(button.label);
403
+ }
404
+
405
+ // Css class
406
+ if (typeof button.cssClass !== undefined && $.trim(button.cssClass) !== '') {
407
+ $button.addClass(button.cssClass);
408
+ } else {
409
+ $button.addClass('btn-default');
410
+ }
411
+
412
+ // Button on click
413
+ $button.on('click', {dialog: this, button: button}, function(event) {
414
+ var dialog = event.data.dialog;
415
+ var button = event.data.button;
416
+ if (typeof button.action === 'function') {
417
+ button.action.call(this, dialog);
418
+ }
419
+
420
+ if (button.autospin) {
421
+ var $button = $(this);
422
+ $button.find('.' + dialog.getNamespace('button-icon')).remove();
423
+ $button.prepend(dialog.createButtonIcon(dialog.getSpinicon()).addClass('icon-spin'));
424
+ }
425
+ });
426
+
427
+ return $button;
428
+ },
429
+ createButtonIcon: function(icon) {
430
+ var $icon = $('<span></span>');
431
+ $icon.addClass(this.getNamespace('button-icon')).addClass(icon);
432
+
433
+ return $icon;
434
+ },
435
+ /**
436
+ * Invoke this only after the dialog is realized.
437
+ *
438
+ * @param {type} enable
439
+ * @returns {undefined}
440
+ */
441
+ enableButtons: function(enable) {
442
+ var $buttons = this.getModalFooter().find('.btn');
443
+ $buttons.prop("disabled", !enable).toggleClass('disabled', !enable);
444
+
445
+ return this;
446
+ },
447
+ /**
448
+ * Invoke this only after the dialog is realized.
449
+ *
450
+ * @param {type} enable
451
+ * @returns {undefined}
452
+ */
453
+ updateClosable: function() {
454
+ if (this.isRealized()) {
455
+ // Backdrop, I did't find a way to change bs3 backdrop option after the dialog is popped up, so here's a new wheel.
456
+ var $theBigMask = this.getModal();
457
+ $theBigMask.off('click').on('click', {dialog: this}, function(event) {
458
+ event.target === this && event.data.dialog.isClosable() && event.data.dialog.close();
459
+ });
460
+
461
+ // Close button
462
+ this.getModalHeader().find('.' + this.getNamespace('close-button')).toggle(this.isClosable());
463
+
464
+ // ESC key support
465
+ $theBigMask.off('keyup').on('keyup', {dialog: this}, function(event) {
466
+ event.which === 27 && event.data.dialog.isClosable() && event.data.dialog.close();
467
+ });
468
+ }
469
+
470
+ return this;
471
+ },
472
+ /**
473
+ * Set handler for modal event 'show'.
474
+ * This is a setter!
475
+ *
476
+ * @param {type} onopen
477
+ * @returns {_L9.BootstrapDialog.prototype}
478
+ */
479
+ onShow: function(onshow) {
480
+ this.options.onshow = onshow;
481
+
482
+ return this;
483
+ },
484
+ /**
485
+ * Set handler for modal event 'hide'.
486
+ * This is a setter!
487
+ *
488
+ * @param {type} onclose
489
+ * @returns {_L9.BootstrapDialog.prototype}
490
+ */
491
+ onHide: function(onhide) {
492
+ this.options.onhide = onhide;
493
+
494
+ return this;
495
+ },
496
+ isRealized: function() {
497
+ return this.realized;
498
+ },
499
+ setRealized: function(realized) {
500
+ this.realized = realized;
501
+
502
+ return this;
503
+ },
504
+ isOpened: function() {
505
+ return this.opened;
506
+ },
507
+ setOpened: function(opened) {
508
+ this.opened = opened;
509
+
510
+ return this;
511
+ },
512
+ handleModalEvents: function() {
513
+ this.getModal().on('show.bs.modal', {dialog: this}, function(event) {
514
+ var dialog = event.data.dialog;
515
+ typeof dialog.options.onshow === 'function' && dialog.options.onshow(dialog);
516
+ dialog.showPageScrollBar(true);
517
+ });
518
+ this.getModal().on('hide.bs.modal', {dialog: this}, function(event) {
519
+ var dialog = event.data.dialog;
520
+ typeof dialog.options.onhide === 'function' && dialog.options.onhide(dialog);
521
+ });
522
+ this.getModal().on('hidden.bs.modal', {dialog: this}, function(event) {
523
+ var dialog = event.data.dialog;
524
+ dialog.isAutodestroy() && $(this).remove();
525
+ dialog.showPageScrollBar(false);
526
+ });
527
+
528
+ return this;
529
+ },
530
+ showPageScrollBar: function(show) {
531
+ $(document.body).toggleClass('modal-open', show);
532
+ },
533
+ realize: function() {
534
+ this.initModalStuff();
535
+ this.getModal().addClass(BootstrapDialog.NAMESPACE)
536
+ .addClass(this.getType())
537
+ .addClass(this.getSize())
538
+ .addClass(this.getCssClass());
539
+ this.getModalHeader().append(this.createHeaderContent());
540
+ this.getModalBody().append(this.createBodyContent());
541
+ this.getModalFooter().append(this.createFooterContent());
542
+ this.getModal().modal({
543
+ backdrop: 'static',
544
+ keyboard: false,
545
+ show: false
546
+ });
547
+ this.handleModalEvents();
548
+ this.setRealized(true);
549
+
550
+ return this;
551
+ },
552
+ open: function() {
553
+ !this.isRealized() && this.realize();
554
+ this.updateClosable();
555
+ this.getModal().modal('show');
556
+ this.setOpened(true);
557
+
558
+ return this;
559
+ },
560
+ close: function() {
561
+ this.getModal().modal('hide');
562
+ if (this.isAutodestroy()) {
563
+ delete BootstrapDialog.dialogs[this.getId()];
564
+ }
565
+ this.setOpened(false);
566
+
567
+ return this;
568
+ }
569
+ };
570
+
571
+ /**
572
+ * RFC4122 version 4 compliant unique id creator.
573
+ *
574
+ * Added by https://github.com/tufanbarisyildirim/
575
+ *
576
+ * @returns {String}
577
+ */
578
+ BootstrapDialog.newGuid = function() {
579
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
580
+ var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
581
+ return v.toString(16);
582
+ });
583
+ };
584
+
585
+ /* ================================================
586
+ * For lazy people
587
+ * ================================================ */
588
+
589
+ /**
590
+ * Shortcut function: show
591
+ *
592
+ * @param {type} options
593
+ * @returns {undefined}
594
+ */
595
+ BootstrapDialog.show = function(options) {
596
+ new BootstrapDialog(options).open();
597
+ };
598
+
599
+ /**
600
+ * Alert window
601
+ *
602
+ * @param {type} message
603
+ * @param {type} callback
604
+ * @returns {undefined}
605
+ */
606
+ BootstrapDialog.alert = function(message, callback) {
607
+ new BootstrapDialog({
608
+ message: message,
609
+ data: {
610
+ 'callback': callback
611
+ },
612
+ closable: false,
613
+ buttons: [{
614
+ label: 'OK',
615
+ action: function(dialog) {
616
+ typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true);
617
+ dialog.close();
618
+ }
619
+ }]
620
+ }).open();
621
+ };
622
+
623
+ /**
624
+ * Confirm window
625
+ *
626
+ * @param {type} message
627
+ * @param {type} callback
628
+ * @returns {undefined}
629
+ */
630
+ BootstrapDialog.confirm = function(message, callback) {
631
+ new BootstrapDialog({
632
+ title: 'Confirmation',
633
+ message: message,
634
+ closable: false,
635
+ data: {
636
+ 'callback': callback
637
+ },
638
+ buttons: [{
639
+ label: 'Cancel',
640
+ action: function(dialog) {
641
+ typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(false);
642
+ dialog.close();
643
+ }
644
+ }, {
645
+ label: 'OK',
646
+ cssClass: 'btn-primary',
647
+ action: function(dialog) {
648
+ typeof dialog.getData('callback') === 'function' && dialog.getData('callback')(true);
649
+ dialog.close();
650
+ }
651
+ }]
652
+ }).open();
653
+ };
654
+}(window.jQuery);
securis/src/main/resources/static/js/catalogs.json
....@@ -1,7 +1,7 @@
11 [ {
22 "name" : "Applications",
33 "resource" : "application",
4
- "list_fields" : [ "name", "description", "creation_timestamp" ],
4
+ "list_fields" : [ "name", "description", "creationTimestamp" ],
55 "fields" : [ {
66 "name" : "id",
77 "display" : "ID",
securis/src/main/resources/static/js/commons.js
....@@ -0,0 +1,224 @@
1
+(function() {
2
+ 'use strict';
3
+
4
+ var app = angular.module('app', [ 'ngRoute', 'ngAnimate', 'ngResource' ]);
5
+
6
+ app.directive(
7
+ 'catalogField',
8
+ function() {
9
+ return {
10
+ restrict : 'A', // only activate on element
11
+ // attribute
12
+ require : '?ngModel', // get a hold of
13
+ // NgModelController
14
+ link : function(scope, element, attrs, ngModel) {
15
+ if (!ngModel)
16
+ return; // do nothing if no ng-model
17
+ // TODO: Replace the hard-coded form ID by the
18
+ // appropiate dynamic field
19
+ scope.catalogForm[attrs.name] = scope.catalogForm['{{field.name}}'];
20
+ scope.catalogForm[attrs.name].$name = attrs.name;
21
+ }
22
+ };
23
+ });
24
+
25
+ app.factory('Catalogs', function($http, $resource) {
26
+ var CatalogsService = {
27
+ resources : {
28
+ application : $resource('/application/:appId', {
29
+ appId : '@id'
30
+ }, {
31
+ update : {
32
+ method : "PUT"
33
+ },
34
+ test: {
35
+ url: '/application/:appId',
36
+ method : "DELETE",
37
+ params : {
38
+ appId : '@id'
39
+ }
40
+ }
41
+ }),
42
+ user : $resource('/user/:userId', {
43
+ userId : '@id'
44
+ }, {
45
+ update : {
46
+ method : "PUT"
47
+ }
48
+ }),
49
+ licensetype : $resource('/licenseType/:licenseTypeId', {
50
+ licenseTypeId : '@id'
51
+ }, {
52
+ update : {
53
+ method : "PUT"
54
+ }
55
+ })
56
+
57
+ },
58
+ list : function(initFn) {
59
+ $http.get('/js/catalogs.json').success(function(data) {
60
+ console.log(data);
61
+ CatalogsService.data = data;
62
+ initFn();
63
+ })
64
+ return CatalogsService;
65
+ },
66
+ getName : function(index) {
67
+ return CatalogsService.data ? CatalogsService.data[index].name
68
+ : '';
69
+ },
70
+ getResource : function(index) {
71
+ return CatalogsService.data ? CatalogsService.data[index].resource
72
+ : '';
73
+ },
74
+ getMetadata : function(index) {
75
+ return CatalogsService.data ? CatalogsService.data[index] : {};
76
+ },
77
+ save: function(catalog, data) {
78
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
79
+ function success(data) {
80
+ console.log('success')
81
+ console.log(data)
82
+ }
83
+ function fail(data, status) {
84
+ console.log('error')
85
+ console.error(data)
86
+ console.error(status)
87
+ }
88
+ if (data.id && data.id !== '')
89
+ return resource.update(data, success, fail)
90
+ else
91
+ return resource.save(data, success, fail)
92
+ },
93
+ remove: function(catalog, data) {
94
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
95
+ function success(data) {
96
+ console.log('success')
97
+ console.log(data)
98
+ }
99
+ function fail(data, status) {
100
+ console.log('error')
101
+ console.error(data)
102
+ console.error(status)
103
+ }
104
+ return resource.remove({}, data, success, fail)
105
+ },
106
+ query: function(catalog, callback) {
107
+ console.log('HI catalog ???? ' + catalog);
108
+ var resource = CatalogsService.resources[catalog.toLowerCase()];
109
+ function success(data) {
110
+ console.log('success')
111
+ console.log(data)
112
+ }
113
+ function fail(data, status) {
114
+ console.log('error')
115
+ console.error(data)
116
+ console.error(status)
117
+ }
118
+ return resource.query({}, success, fail);
119
+ }
120
+ }
121
+
122
+ return CatalogsService;
123
+
124
+ });
125
+
126
+ app.controller('CatalogsCtrl', [
127
+ '$scope',
128
+ '$http',
129
+ 'Catalogs',
130
+ function($scope, $http, Catalogs) {
131
+ $scope.formu = {};
132
+ $scope.catalogIndex = 0;
133
+ $scope.catalogs = Catalogs.list(function() {
134
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
135
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
136
+ });
137
+
138
+ $scope.catalogMetadata = {};
139
+ $scope.selectCatalog = function(index, $event) {
140
+ $scope.catalogIndex = index;
141
+ $scope.catalogMetadata = Catalogs.getMetadata($scope.catalogIndex);
142
+ $scope.list = Catalogs.query(Catalogs.getResource($scope.catalogIndex));
143
+ console.log($event);
144
+ }
145
+ $scope.edit = function(data) {
146
+ $scope.showForm = true;
147
+ $scope.isNew = false;
148
+ for (var k in data) {
149
+ if (k.indexOf('$') !== 0) $scope.formu[k] = data[k]
150
+ }
151
+ // TODO: Load in formu values for Form
152
+ // $scope.formu = {};
153
+ }
154
+ $scope.delete = function(data) {
155
+ BootstrapDialog.confirm('The record will be deleted, are you sure?', function(result){
156
+ if(result) {
157
+ var catalogName = Catalogs.getResource($scope.catalogIndex);
158
+ var promise = Catalogs.remove(catalogName, data).$promise;
159
+ promise.then(function(data) {
160
+ $scope.list = Catalogs.query(catalogName);
161
+ });
162
+ }
163
+ });
164
+ $scope.showForm = false;
165
+ $scope.isNew = false;
166
+ // TODO: Load in formu values for Form
167
+ // $scope.formu = {};
168
+ }
169
+
170
+ } ]);
171
+
172
+ app.controller('CatalogFormCtrl', [ '$scope', '$http', 'Catalogs',
173
+ function($scope, $http, Catalogs) {
174
+ $scope.showForm = false;
175
+ $scope.scope = $scope;
176
+ console.log('Form: currentCatalog:' + $scope.cataLogIndex);
177
+
178
+ $scope.editNew = function() {
179
+ $scope.showForm = true;
180
+ $scope.isNew = true;
181
+ // $scope.formu = {};
182
+ }
183
+ $scope.cancel = function() {
184
+ $scope.showForm = false;
185
+ }
186
+
187
+ $scope.saveCatalog = function() {
188
+ if ($scope.catalogForm.$invalid) {
189
+ alert(JSON.stringify($scope.catalogForm))
190
+ } else {
191
+ var catalogName = Catalogs.getResource($scope.catalogIndex);
192
+ var promise = Catalogs.save(catalogName, $scope.formu).$promise;
193
+ promise.then(function(data) {
194
+ $scope.$parent.list = Catalogs.query(catalogName);
195
+ });
196
+ }
197
+ }
198
+ } ]);
199
+
200
+ app.controller('CatalogListCtrl', [ '$scope', '$http', '$filter', 'Catalogs',
201
+ function($scope, $http, $filter, Catalogs) {
202
+ console.log('List: currentCatalog: ' + $scope.currentCatalog);
203
+ var _indexOfField = function(name) {
204
+ if (!$scope.catalogMetadata) return -1;
205
+ for (var i = $scope.catalogMetadata.fields.length - 1; i >= 0 && $scope.catalogMetadata.fields[i].name !== name; i--);
206
+ return i;
207
+ }
208
+
209
+ $scope.print = function(name, value) {
210
+ var index = _indexOfField(name);
211
+ if (index === -1) return value;
212
+ var type = $scope.catalogMetadata.fields[index].type;
213
+
214
+ return type === 'date' ? $filter('date')(value, 'yyyy-MM-dd') : value;
215
+ }
216
+
217
+ $scope.display = function(name) {
218
+ var index = _indexOfField(name);
219
+ return index === -1 ? '' : $scope.catalogMetadata.fields[index].display;
220
+ }
221
+
222
+ } ]);
223
+
224
+})();
securis/src/main/resources/static/js/toaster.js
....@@ -0,0 +1,145 @@
1
+'use strict';
2
+
3
+/*
4
+ * AngularJS Toaster
5
+ * Version: 0.4.1
6
+ *
7
+ * Copyright 2013 Jiri Kavulak.
8
+ * All Rights Reserved.
9
+ * Use, reproduction, distribution, and modification of this code is subject to the terms and
10
+ * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
11
+ *
12
+ * Author: Jiri Kavulak
13
+ * Related to project of John Papa and Hans Fjällemark
14
+ */
15
+
16
+angular.module('toaster', ['ngAnimate'])
17
+.service('toaster', ['$rootScope', function ($rootScope) {
18
+ this.pop = function (type, title, body, timeout, bodyOutputType) {
19
+ this.toast = {
20
+ type: type,
21
+ title: title,
22
+ body: body,
23
+ timeout: timeout,
24
+ bodyOutputType: bodyOutputType
25
+ };
26
+ $rootScope.$broadcast('toaster-newToast');
27
+ };
28
+}])
29
+.constant('toasterConfig', {
30
+ 'tap-to-dismiss': true,
31
+ 'newest-on-top': true,
32
+ //'fade-in': 1000, // done in css
33
+ //'on-fade-in': undefined, // not implemented
34
+ //'fade-out': 1000, // done in css
35
+ // 'on-fade-out': undefined, // not implemented
36
+ //'extended-time-out': 1000, // not implemented
37
+ 'time-out': 5000, // Set timeOut and extendedTimeout to 0 to make it sticky
38
+ 'icon-classes': {
39
+ error: 'toast-error',
40
+ info: 'toast-info',
41
+ success: 'toast-success',
42
+ warning: 'toast-warning'
43
+ },
44
+ 'body-output-type': '', // Options: '', 'trustedHtml', 'template'
45
+ 'body-template': 'toasterBodyTmpl.html',
46
+ 'icon-class': 'toast-info',
47
+ 'position-class': 'toast-top-right',
48
+ 'title-class': 'toast-title',
49
+ 'message-class': 'toast-message'
50
+ })
51
+.directive('toasterContainer', ['$compile', '$timeout', '$sce', 'toasterConfig', 'toaster',
52
+function ($compile, $timeout, $sce, toasterConfig, toaster) {
53
+ return {
54
+ replace: true,
55
+ restrict: 'EA',
56
+ link: function (scope, elm, attrs){
57
+
58
+ var id = 0;
59
+
60
+ var mergedConfig = toasterConfig;
61
+ if (attrs.toasterOptions) {
62
+ angular.extend(mergedConfig, scope.$eval(attrs.toasterOptions));
63
+ }
64
+
65
+ scope.config = {
66
+ position: mergedConfig['position-class'],
67
+ title: mergedConfig['title-class'],
68
+ message: mergedConfig['message-class'],
69
+ tap: mergedConfig['tap-to-dismiss']
70
+ };
71
+
72
+ function addToast (toast){
73
+ toast.type = mergedConfig['icon-classes'][toast.type];
74
+ if (!toast.type)
75
+ toast.type = mergedConfig['icon-class'];
76
+
77
+ id++;
78
+ angular.extend(toast, { id: id });
79
+
80
+ switch(toast.bodyOutputType)
81
+ {
82
+ case 'trustedHtml':
83
+ toast.html = $sce.trustAsHtml(toast.body);
84
+ break;
85
+ case 'template':
86
+ toast.bodyTemplate = mergedConfig['body-template'];
87
+ break;
88
+ }
89
+
90
+ var timeout = typeof(toast.timeout) == "number" ? toast.timeout : mergedConfig['time-out'];
91
+ if (timeout > 0)
92
+ setTimeout(toast, timeout);
93
+
94
+ if (mergedConfig['newest-on-top'] === true)
95
+ scope.toasters.unshift(toast);
96
+ else
97
+ scope.toasters.push(toast);
98
+ }
99
+
100
+ function setTimeout(toast, time){
101
+ toast.timeout= $timeout(function (){
102
+ scope.removeToast(toast.id);
103
+ }, time);
104
+ }
105
+
106
+ scope.toasters = [];
107
+ scope.$on('toaster-newToast', function () {
108
+ addToast(toaster.toast);
109
+ });
110
+ },
111
+ controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
112
+
113
+ $scope.stopTimer = function(toast){
114
+ if(toast.timeout)
115
+ $timeout.cancel(toast.timeout);
116
+ };
117
+
118
+ $scope.removeToast = function (id){
119
+ var i = 0;
120
+ for (i; i < $scope.toasters.length; i++){
121
+ if($scope.toasters[i].id === id)
122
+ break;
123
+ }
124
+ $scope.toasters.splice(i, 1);
125
+ };
126
+
127
+ $scope.remove = function(id){
128
+ if ($scope.config.tap === true){
129
+ $scope.removeToast(id);
130
+ }
131
+ };
132
+ }],
133
+ template:
134
+ '<div id="toast-container" ng-class="config.position">' +
135
+ '<div ng-repeat="toaster in toasters" class="toast" ng-class="toaster.type" ng-click="remove(toaster.id)" ng-mouseover="stopTimer(toaster)">' +
136
+ '<div ng-class="config.title">{{toaster.title}}</div>' +
137
+ '<div ng-class="config.message" ng-switch on="toaster.bodyOutputType">' +
138
+ '<div ng-switch-when="trustedHtml" ng-bind-html="toaster.html"></div>' +
139
+ '<div ng-switch-when="template"><div ng-include="toaster.bodyTemplate"></div></div>' +
140
+ '<div ng-switch-default >{{toaster.body}}</div>' +
141
+ '</div>' +
142
+ '</div>' +
143
+ '</div>'
144
+ };
145
+}]);