2 * UI tools and directives.
4 angular.module('egUiMod', ['egCoreMod', 'ui.bootstrap'])
8 * <input focus-me="iAmOpen"/>
9 * $scope.iAmOpen = true;
13 function($timeout , $parse) {
15 link: function(scope, element, attrs) {
16 var model = $parse(attrs.focusMe);
17 scope.$watch(model, function(value) {
19 $timeout(function() {element[0].focus()});
21 element.bind('blur', function() {
22 scope.$apply(model.assign(scope, false));
29 * <input blur-me="pleaseBlurMe"/>
30 * $scope.pleaseBlurMe = true
31 * Useful for de-focusing when no other obvious focus target exists
35 function($timeout , $parse) {
37 link: function(scope, element, attrs) {
38 var model = $parse(attrs.blurMe);
39 scope.$watch(model, function(value) {
41 $timeout(function() {element[0].blur()});
43 element.bind('focus', function() {
44 scope.$apply(model.assign(scope, false));
51 // <input select-me="iWantToBeSelected"/>
52 // $scope.iWantToBeSelected = true;
53 .directive('selectMe',
55 function($timeout , $parse) {
57 link: function(scope, element, attrs) {
58 var model = $parse(attrs.selectMe);
59 scope.$watch(model, function(value) {
61 $timeout(function() {element[0].select()});
63 element.bind('blur', function() {
64 scope.$apply(model.assign(scope, false));
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();
83 * egAlertDialog.open({message : 'hello {{name}}'}).result.then(
84 * function() { console.log('alert closed') });
86 .factory('egAlertDialog',
88 ['$modal','$interpolate',
89 function($modal , $interpolate) {
92 service.open = function(message, msg_scope) {
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()
111 * egConfirmDialog.open("some message goes {{here}}", {
112 * here : 'foo', ok : function() {}, cancel : function() {}});
114 .factory('egConfirmDialog',
116 ['$modal','$interpolate',
117 function($modal, $interpolate) {
120 service.open = function(title, message, msg_scope) {
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()
131 $scope.cancel = function() {
132 if (msg_scope.cancel) msg_scope.cancel();
133 $modalInstance.dismiss();
144 * egPromptDialog.open(
145 * "prompt message goes {{here}}",
146 * promptValue, // optional
149 * ok : function(value) {console.log(value)},
150 * cancel : function() {console.log('prompt denied')}
154 .factory('egPromptDialog',
156 ['$modal','$interpolate',
157 function($modal, $interpolate) {
160 service.open = function(message, promptValue, msg_scope) {
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 || ''};
168 $scope.ok = function() {
169 if (msg_scope.ok) msg_scope.ok($scope.args.value);
170 $modalInstance.close()
172 $scope.cancel = function() {
173 if (msg_scope.cancel) msg_scope.cancel();
174 $modalInstance.dismiss();
184 .directive('aDisabled', function() {
187 compile: function(tElement, tAttrs, transclude) {
189 tAttrs["ngClick"] = ("ng-click", "!("+tAttrs["aDisabled"]+") && ("+tAttrs["ngClick"]+")");
191 //Toggle "disabled" to class when aDisabled becomes true
192 return function (scope, iElement, iAttrs) {
193 scope.$watch(iAttrs["aDisabled"], function(newValue) {
194 if (newValue !== undefined) {
195 iElement.toggleClass("disabled", newValue);
199 //Disable href on click
200 iElement.on("click", function(e) {
201 if (scope.$eval(iAttrs["aDisabled"])) {
211 * Nested org unit selector modeled as a Bootstrap dropdown button.
213 .directive('egOrgSelector', function() {
217 replace : true, // makes styling easier
219 selected : '=', // defaults to workstation or root org
221 // Each org unit is passed into this function and, for
222 // any org units where the response value is true, the
223 // org unit will not be added to the selector.
226 // Each org unit is passed into this function and, for
227 // any org units where the response value is true, the
228 // org unit will not be available for selection.
231 // Caller can either $watch(selected, ..) or register an
235 // optional primary drop-down button label
239 // any reason to move this into a TT2 template?
241 '<div class="btn-group eg-org-selector" dropdown>'
242 + '<button type="button" class="btn btn-default dropdown-toggle">'
243 + '<span style="padding-right: 5px;">{{getSelectedName()}}</span>'
244 + '<span class="caret"></span>'
246 + '<ul class="dropdown-menu">'
247 + '<li ng-repeat="org in orgList" ng-hide="hiddenTest(org.id)">'
248 + '<a href ng-click="orgChanged(org)" a-disabled="disableTest(org.id)" '
249 + 'style="padding-left: {{org.depth * 10 + 5}}px">'
250 + '{{org.shortname}}'
256 controller : ['$scope','$timeout','egOrg','egAuth',
257 function($scope , $timeout , egOrg , egAuth) {
259 // avoid linking the full fleshed tree to the scope by
260 // tossing in a flattened list.
261 $scope.orgList = egOrg.list().map(function(org) {
264 shortname : org.shortname(),
265 depth : org.ou_type().depth()
269 $scope.getSelectedName = function() {
271 return $scope.selected.shortname();
275 $scope.orgChanged = function(org) {
276 $scope.selected = egOrg.get(org.id);
277 if ($scope.onchange) $scope.onchange($scope.selected);
280 if (!$scope.selected)
281 $scope.selected = egOrg.get(egAuth.user().ws_ou());
288 http://stackoverflow.com/questions/18061757/angular-js-and-html5-date-input-value-how-to-get-firefox-to-show-a-readable-d
290 This directive allows us to use html5 input type="date" (for Chrome) and
291 gracefully fall back to a regular ISO text input for Firefox.
292 It also allows us to abstract away some browser finickiness.
296 function(dateFilter) {
299 template: '<input type="date"></input>',
301 link: function(scope, elm, attrs, ngModelCtrl) {
303 // since this is a date-only selector, set the time
304 // portion to 00:00:00, which should better match the
305 // user's expectations. Note this allows us to retain
307 function strip_time(date) {
308 if (!date) date = new Date();
312 date.setMilliseconds(0);
316 ngModelCtrl.$formatters.unshift(function (modelValue) {
317 // apply strip_time here in case the user never
318 // modifies the date value.
319 return dateFilter(strip_time(modelValue), 'yyyy-MM-dd');
322 ngModelCtrl.$parsers.unshift(function(viewValue) {
323 return strip_time(new Date(viewValue));