]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/services/ui.js
LP#1402797 Attempt to implement disabling tests for orgs in the magic dropdown
[Evergreen.git] / Open-ILS / web / js / ui / default / staff / services / ui.js
1 /**
2   * UI tools and directives.
3   */
4 angular.module('egUiMod', ['egCoreMod', 'ui.bootstrap'])
5
6
7 /**
8  * <input focus-me="iAmOpen"/>
9  * $scope.iAmOpen = true;
10  */
11 .directive('focusMe', 
12        ['$timeout','$parse', 
13 function($timeout , $parse) {
14     return {
15         link: function(scope, element, attrs) {
16             var model = $parse(attrs.focusMe);
17             scope.$watch(model, function(value) {
18                 if(value === true) 
19                     $timeout(function() {element[0].focus()});
20             });
21             element.bind('blur', function() {
22                 scope.$apply(model.assign(scope, false));
23             })
24         }
25     };
26 }])
27
28 /**
29  * <input blur-me="pleaseBlurMe"/>
30  * $scope.pleaseBlurMe = true
31  * Useful for de-focusing when no other obvious focus target exists
32  */
33 .directive('blurMe', 
34        ['$timeout','$parse', 
35 function($timeout , $parse) {
36     return {
37         link: function(scope, element, attrs) {
38             var model = $parse(attrs.blurMe);
39             scope.$watch(model, function(value) {
40                 if(value === true) 
41                     $timeout(function() {element[0].blur()});
42             });
43             element.bind('focus', function() {
44                 scope.$apply(model.assign(scope, false));
45             })
46         }
47     };
48 }])
49
50
51 // <input select-me="iWantToBeSelected"/>
52 // $scope.iWantToBeSelected = true;
53 .directive('selectMe', 
54        ['$timeout','$parse', 
55 function($timeout , $parse) {
56     return {
57         link: function(scope, element, attrs) {
58             var model = $parse(attrs.selectMe);
59             scope.$watch(model, function(value) {
60                 if(value === true) 
61                     $timeout(function() {element[0].select()});
62             });
63             element.bind('blur', function() {
64                 scope.$apply(model.assign(scope, false));
65             })
66         }
67     };
68 }])
69
70
71 // 'reverse' filter 
72 // <div ng-repeat="item in items | reverse">{{item.name}}</div>
73 // http://stackoverflow.com/questions/15266671/angular-ng-repeat-in-reverse
74 // TODO: perhaps this should live elsewhere
75 .filter('reverse', function() {
76     return function(items) {
77         return items.slice().reverse();
78     };
79 })
80
81
82 /**
83  * egAlertDialog.open({message : 'hello {{name}}'}).result.then(
84  *     function() { console.log('alert closed') });
85  */
86 .factory('egAlertDialog', 
87
88         ['$modal','$interpolate',
89 function($modal , $interpolate) {
90     var service = {};
91
92     service.open = function(message, msg_scope) {
93         return $modal.open({
94             templateUrl: './share/t_alert_dialog',
95             controller: ['$scope', '$modalInstance',
96                 function($scope, $modalInstance) {
97                     $scope.message = $interpolate(message)(msg_scope);
98                     $scope.ok = function() {
99                         if (msg_scope && msg_scope.ok) msg_scope.ok();
100                         $modalInstance.close()
101                     }
102                 }
103             ]
104         });
105     }
106
107     return service;
108 }])
109
110 /**
111  * egConfirmDialog.open("some message goes {{here}}", {
112  *  here : 'foo', ok : function() {}, cancel : function() {}});
113  */
114 .factory('egConfirmDialog', 
115     
116        ['$modal','$interpolate',
117 function($modal, $interpolate) {
118     var service = {};
119
120     service.open = function(title, message, msg_scope) {
121         return $modal.open({
122             templateUrl: './share/t_confirm_dialog',
123             controller: ['$scope', '$modalInstance',
124                 function($scope, $modalInstance) {
125                     $scope.title = $interpolate(title)(msg_scope);
126                     $scope.message = $interpolate(message)(msg_scope);
127                     $scope.ok = function() {
128                         if (msg_scope.ok) msg_scope.ok();
129                         $modalInstance.close()
130                     }
131                     $scope.cancel = function() {
132                         if (msg_scope.cancel) msg_scope.cancel();
133                         $modalInstance.dismiss();
134                     }
135                 }
136             ]
137         })
138     }
139
140     return service;
141 }])
142
143 /**
144  * egPromptDialog.open(
145  *    "prompt message goes {{here}}", 
146  *    promptValue,  // optional
147  *    {
148  *      here : 'foo',  
149  *      ok : function(value) {console.log(value)}, 
150  *      cancel : function() {console.log('prompt denied')}
151  *    }
152  *  );
153  */
154 .factory('egPromptDialog', 
155     
156        ['$modal','$interpolate',
157 function($modal, $interpolate) {
158     var service = {};
159
160     service.open = function(message, promptValue, msg_scope) {
161         return $modal.open({
162             templateUrl: './share/t_prompt_dialog',
163             controller: ['$scope', '$modalInstance',
164                 function($scope, $modalInstance) {
165                     $scope.message = $interpolate(message)(msg_scope);
166                     $scope.args = {value : promptValue || ''};
167                     $scope.focus = true;
168                     $scope.ok = function() {
169                         if (msg_scope.ok) msg_scope.ok($scope.args.value);
170                         $modalInstance.close()
171                     }
172                     $scope.cancel = function() {
173                         if (msg_scope.cancel) msg_scope.cancel();
174                         $modalInstance.dismiss();
175                     }
176                 }
177             ]
178         })
179     }
180
181     return service;
182 }])
183
184
185 /**
186  * Nested org unit selector modeled as a Bootstrap dropdown button.
187  */
188 .directive('egOrgSelector', function() {
189     return {
190         restrict : 'AE',
191         transclude : true,
192         replace : true, // makes styling easier
193         scope : {
194             selected : '=', // defaults to workstation or root org
195             
196             // Each org unit is passed into this function and, for
197             // any org units where the response value is true, the
198             // org unit will not be added to the selector.
199             hiddenTest : '&',
200
201             // Each org unit is passed into this function and, for
202             // any org units where the response value is true, the
203             // org unit will not be available for selection.
204             disableTest : '&',
205
206             // Caller can either $watch(selected, ..) or register an
207             // onchange handler.
208             onchange : '=',
209
210             // optional primary drop-down button label
211             label : '@'
212         },
213
214         // any reason to move this into a TT2 template?
215         template : 
216             '<div class="btn-group eg-org-selector" dropdown>'
217             + '<button type="button" class="btn btn-default dropdown-toggle">'
218              + '<span style="padding-right: 5px;">{{getSelectedName()}}</span>'
219              + '<span class="caret"></span>'
220            + '</button>'
221            + '<ul class="dropdown-menu">'
222              + '<li ng-repeat="org in orgList" ng-hide="hiddenTest(org.id)">'
223                + '<a href ng-click="orgChanged(org)" ng-disabled="disableTest(org.id)" '
224                  + 'style="padding-left: {{org.depth * 10 + 5}}px">'
225                  + '{{org.shortname}}'
226                + '</a>'
227              + '</li>'
228            + '</ul>'
229           + '</div>',
230
231         controller : ['$scope','$timeout','egOrg','egAuth',
232               function($scope , $timeout , egOrg , egAuth) {
233
234             // avoid linking the full fleshed tree to the scope by 
235             // tossing in a flattened list.
236             $scope.orgList = egOrg.list().map(function(org) {
237                 return {
238                     id : org.id(),
239                     shortname : org.shortname(), 
240                     depth : org.ou_type().depth()
241                 }
242             });
243
244             $scope.getSelectedName = function() {
245                 if ($scope.selected)
246                     return $scope.selected.shortname();
247                 return $scope.label;
248             }
249
250             $scope.orgChanged = function(org) {
251                 $scope.selected = egOrg.get(org.id);
252                 if ($scope.onchange) $scope.onchange($scope.selected);
253             }
254
255             if (!$scope.selected)
256                 $scope.selected = egOrg.get(egAuth.user().ws_ou());
257         }]
258     }
259 })
260
261
262 /*
263 http://stackoverflow.com/questions/18061757/angular-js-and-html5-date-input-value-how-to-get-firefox-to-show-a-readable-d
264
265 This directive allows us to use html5 input type="date" (for Chrome) and 
266 gracefully fall back to a regular ISO text input for Firefox.
267 It also allows us to abstract away some browser finickiness.
268 */
269 .directive(
270     'egDateInput',
271     function(dateFilter) {
272         return {
273             require: 'ngModel',
274             template: '<input type="date"></input>',
275             replace: true,
276             link: function(scope, elm, attrs, ngModelCtrl) {
277
278                 // since this is a date-only selector, set the time
279                 // portion to 00:00:00, which should better match the
280                 // user's expectations.  Note this allows us to retain
281                 // the timezone.
282                 function strip_time(date) {
283                     if (!date) date = new Date();
284                     date.setHours(0);
285                     date.setMinutes(0);
286                     date.setSeconds(0);
287                     date.setMilliseconds(0);
288                     return date;
289                 }
290
291                 ngModelCtrl.$formatters.unshift(function (modelValue) {
292                     // apply strip_time here in case the user never 
293                     // modifies the date value.
294                     return dateFilter(strip_time(modelValue), 'yyyy-MM-dd');
295                 });
296                 
297                 ngModelCtrl.$parsers.unshift(function(viewValue) {
298                     return strip_time(new Date(viewValue));
299                 });
300             },
301         };
302 })