]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/admin/serials/app.js
Web Client: Make Patron Email Clickable
[Evergreen.git] / Open-ILS / web / js / ui / default / staff / admin / serials / app.js
1 angular.module('egSerialsAdmin',
2     ['ngRoute', 'ui.bootstrap', 'egCoreMod', 'egUiMod', 'egGridMod'])
3
4 .config(['$routeProvider','$locationProvider','$compileProvider', 
5  function($routeProvider , $locationProvider , $compileProvider) {
6
7     $locationProvider.html5Mode(true);
8     $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|mailto|blob):/); 
9     var resolver = {delay : function(egStartup) {return egStartup.go()}};
10
11     $routeProvider.when('/admin/serials/templates', {
12         templateUrl: './admin/serials/t_templates',
13         controller: 'TemplatesCtrl',
14         resolve : resolver
15     });
16
17     // default page 
18     $routeProvider.otherwise({
19         templateUrl : './admin/serials/t_splash',
20         resolve : resolver
21     });
22 }])
23
24 // cheating
25 .factory("sharedScope",function(){
26     return {};
27 })
28
29 .factory('templateSvc', 
30        ['egCore','$q','$uibModal','ngToast',
31 function(egCore , $q , $uibModal , ngToast ) {
32
33     var service = {
34     };
35
36     service.create_or_edit_template = function(id,ou,cb) {
37         $uibModal.open({
38             template: '<eg-serials-template template_id="' + id + '" owning_lib="' + ou + '"></eg-serials-template>',
39             backdrop: 'static',
40             controller:
41                    ['sharedScope','$uibModalInstance',
42             function(sharedScope , $uibModalInstance ) {
43                 sharedScope.close_modal = function(count) { $uibModalInstance.close({}) }
44             }],
45             windowClass: 'app-modal-window',
46             backdrop: 'static',
47             keyboard: false
48         }).result.then(
49             function(args) {
50                 if (cb) { cb(); }
51             }
52         );
53     }
54
55     service.delete_template = function(id,cb) {
56         return egCore.pcrud.search('act',
57             {id : id},
58             null, {atomic : true}
59         ).then(function(resp) {
60             var evt = egCore.evt.parse(resp);
61             if (evt) { console.log(evt); }
62             if (!evt && resp && resp.length > 0) {
63                 return resp[0];
64             }
65         }).then(function(resp) {
66             resp.isdeleted(true); // needed?
67             return egCore.pcrud.remove(resp);
68         }).then(
69             function(resp) {
70                 console.log(resp);
71                 ngToast.success(egCore.strings.SERIALS_TEMPLATE_SUCCESS_DELETE);
72             },function(resp) {
73                 console.log(resp);
74                 ngToast.danger(egCore.strings.SERIALS_TEMPLATE_FAIL_DELETE);
75             }
76         ).finally(function() {
77             if (cb) { cb(); }
78         });
79     }
80
81     return service;
82 }])
83
84 .factory('itemSvc', 
85        ['egCore','$q',
86 function(egCore , $q) {
87
88     var service = {
89     };
90
91     service.get_locations = function(orgs) {
92         return egCore.pcrud.search('acpl',
93             {
94                 owning_lib : orgs,
95                 deleted    : 'f'
96             },
97             {
98                 flesh : 1,
99                 flesh_fields : {
100                     'acpl' : ['owning_lib']
101                 },
102                 order_by : { acpl : 'name' }
103             }, {atomic : true}
104         );
105     };
106
107     service.get_statuses = function() {
108         if (egCore.env.ccs)
109             return $q.when(egCore.env.ccs.list);
110
111         return egCore.pcrud.retrieveAll('ccs', {order_by : { ccs : 'name' }}, {atomic : true}).then(
112             function(list) {
113                 egCore.env.absorbList(list, 'ccs');
114                 return list;
115             }
116         );
117
118     };
119
120     service.get_circ_mods = function() {
121         if (egCore.env.ccm)
122             return $q.when(egCore.env.ccm.list);
123
124         return egCore.pcrud.retrieveAll('ccm', {}, {atomic : true}).then(
125             function(list) {
126                 egCore.env.absorbList(list, 'ccm');
127                 return list;
128             }
129         );
130
131     };
132
133     service.get_circ_types = function() {
134         if (egCore.env.citm)
135             return $q.when(egCore.env.citm.list);
136
137         return egCore.pcrud.retrieveAll('citm', {}, {atomic : true}).then(
138             function(list) {
139                 egCore.env.absorbList(list, 'citm');
140                 return list;
141             }
142         );
143
144     };
145
146     service.get_age_protects = function() {
147         if (egCore.env.crahp)
148             return $q.when(egCore.env.crahp.list);
149
150         return egCore.pcrud.retrieveAll('crahp', {}, {atomic : true}).then(
151             function(list) {
152                 egCore.env.absorbList(list, 'crahp');
153                 return list;
154             }
155         );
156
157     };
158
159     service.get_floating_groups = function() {
160         if (egCore.env.cfg)
161             return $q.when(egCore.env.cfg.list);
162
163         return egCore.pcrud.retrieveAll('cfg', {}, {atomic : true}).then(
164             function(list) {
165                 egCore.env.absorbList(list, 'cfg');
166                 return list;
167             }
168         );
169
170     };
171
172     service.bmp_parts = {};
173     service.get_parts = function(rec) {
174         if (service.bmp_parts[rec])
175             return $q.when(service.bmp_parts[rec]);
176
177         return egCore.pcrud.search('bmp',
178             {record : rec, deleted : 'f'},
179             null, {atomic : true}
180         ).then(function(list) {
181             service.bmp_parts[rec] = list;
182             return list;
183         });
184
185     };
186
187     return service;
188 }])
189
190 .controller('TemplatesCtrl', 
191        ['$scope','$q','$window','$routeParams','$location','$timeout','egCore','egNet','itemSvc','templateSvc',
192         'egGridDataProvider',
193 function($scope , $q , $window , $routeParams , $location , $timeout , egCore , egNet , itemSvc , templateSvc ,
194          egGridDataProvider ) {
195
196     function current_query() {
197         var filter = {
198             'owning_lib' : egCore.org.descendants($scope.context_ou.id(), true)
199         };
200         return filter;
201     }
202
203     function refresh_page() {
204         $scope.grid_controls.setQuery(current_query());
205     }
206
207     $scope.grid_actions = {
208         create_template : function() {
209             templateSvc.create_or_edit_template(null,$scope.context_ou.id(),refresh_page);
210         },
211         edit_template : function(items) {
212             templateSvc.create_or_edit_template(items[0].id,$scope.context_ou.id(),refresh_page);
213         },
214         delete_template : function(items) {
215             var promises = [];
216             angular.forEach(items,function(item) {
217                 promises.push(templateSvc.delete_template(item.id));
218             });
219             $q.all(promises).then(function() {
220                 refresh_page();
221             });
222         }
223     }
224     $scope.grid_controls = {
225         activateItem : function(item) {
226             templateSvc.create_or_edit_template(item.id,$scope.context_ou.id(),refresh_page);
227         },
228         setQuery : function(x) { return x || current_query(); },
229         setSort : function() { return ['name','id'] }
230     }
231
232     $scope.need_one_selected = function() {
233         var items = $scope.grid_controls.selectedItems();
234         if (items.length == 1) return false;
235         return true;
236     };
237
238     // called after any egGridActions action occurs
239     $scope.grid_actions.refresh = refresh_page;
240
241     // re-draw the grid when user changes the org selector
242     $scope.context_ou = egCore.org.get(egCore.auth.user().ws_ou());
243     $scope.$watch('context_ou', function(newVal, oldVal) {
244         if (newVal && newVal != oldVal) 
245             refresh_page();
246     });
247
248     refresh_page();
249
250 }])
251
252 .directive("egSerialsTemplate", function () {
253     return {
254         restrict: 'E',
255         replace: true,
256         template: '<div ng-include="'+"'/eg/staff/admin/serials/t_attr_edit'"+'"></div>',
257         scope: {
258             templateId: '=',
259              owningLib: '='
260         },
261         controller : ['$scope','$q','$window','itemSvc','egCore','ngToast','sharedScope',
262             function ( $scope , $q , $window , itemSvc , egCore , ngToast , sharedScope ) {
263
264                 $scope.close_modal = function() {
265                     if ($scope.dirty && !window.confirm(egCore.strings.CONFIRM_DIRTY_EXIT)) {
266                         return;
267                     }
268                     //console.log('unsetting dirty for close_modal');
269                     $scope.dirty = false;
270                     sharedScope.close_modal();
271                 };
272
273                 $scope.defaults = { // If defaults are not set at all, allow everything
274                     attributes : {
275                         status : true,
276                         loan_duration : true,
277                         fine_level : true,
278                         alerts : true,
279                         deposit : true,
280                         deposit_amount : true,
281                         opac_visible : true,
282                         price : true,
283                         circulate : true,
284                         mint_condition : true,
285                         circ_lib : true,
286                         ref : true,
287                         circ_modifier : true,
288                         circ_as_type : true,
289                         location : true,
290                         holdable : true,
291                         age_protect : true,
292                         floating : true
293                     }
294                 };
295
296                 $scope.fetchDefaults = function () {
297                     egCore.hatch.getItem('serials.copy.defaults').then(function(t) {
298                         if (t) {
299                             $scope.defaults = t;
300                         }
301                     });
302                 }
303                 $scope.fetchDefaults();
304
305                 //console.log('unsetting dirty by default');
306                 $scope.dirty = false;
307                 $scope.$watch('dirty',
308                     function(newVal, oldVal) {
309                         //console.log('watching dirty');
310                         //console.log('...oldVal',oldVal);
311                         //console.log('...newVal',newVal);
312                         //console.log('...fetching',$scope.fetching);
313                         if (newVal && $scope.fetching) {
314                             // KLUDGY
315                             // so after fetchTemplate -> applyTemplate
316                             // the working watches will fire and set
317                             // dirty to true.  We'll undo that at this
318                             // point.
319                             //console.log('unsetting dirty via kludge');
320                             $scope.fetching = false;
321                             $scope.dirty = false;
322                             newVal = false;
323                         }
324                         if (newVal && newVal != oldVal) {
325                             $($window).on('beforeunload.template', function(){
326                                 return 'There is unsaved template data!'
327                             });
328                         } else {
329                             $($window).off('beforeunload.template');
330                         }
331                     }
332                 );
333
334                 $scope.applyTemplate = function() {
335                     //console.log('applying...');
336                     angular.forEach($scope.hashed_template, function (v,k) {
337                         //console.log(k,v);
338                         if (k == 'circ_lib') {
339                             $scope.working[k] = egCore.org.get(v);
340                         } else if (!angular.isObject(v)) {
341                             $scope.working[k] = angular.copy(v);
342                         } else {
343                             angular.forEach(v, function (sv,sk) {
344                                 if (!(k in $scope.working))
345                                     $scope.working[k] = {};
346                                 $scope.working[k][sk] = angular.copy(sv);
347                             });
348                         }
349                     });
350                     //console.log('unsetting dirty via applyTemplate');
351                     $scope.dirty = false;
352                 }
353
354                 $scope.fetching = false;
355                 $scope.fetchTemplate = function () {
356                     $scope.fetching = true;
357                     return egCore.pcrud.search('act',
358                         {id : $scope.templateId},
359                         null, {atomic : true}
360                     ).then(function(resp) {
361                         var evt = egCore.evt.parse(resp);
362                         if (evt) { console.log(evt); }
363                         if (!evt && resp && resp.length > 0) {
364                             $scope.fm_template =  resp[0];
365                             $scope.hashed_template = egCore.idl.toHash(resp[0]); 
366                             $scope.applyTemplate();
367                         } else {
368                             console.log('new template');
369                         }
370                     });
371                 }
372  
373                 $scope.saveTemplate = function() {
374                     var tmpl = {};
375         
376                     angular.forEach($scope.working, function (v,k) {
377                         if (angular.isObject(v)) { // we'll use the pkey
378                             if (v.id) v = v.id();
379                             else if (v.code) v = v.code();
380                         }
381         
382                         tmpl[k] = v;
383                     });
384         
385                     $scope.hashed_template = tmpl;
386
387                     var act_obj = $scope.fm_template || new egCore.idl.act() ;
388                     //console.log('consuming...');
389                     angular.forEach($scope.hashed_template, function (v,k) {
390                         //console.log(k,v);
391                         if (typeof act_obj[k] == 'function') {
392                             act_obj[k](v);
393                         } else {
394                             console.log('something wrong here',k,act_obj[k]);
395                         }
396                     });
397                     if ($scope.fm_template) {
398                         console.log('edit');
399                         act_obj.ischanged('t');
400                         act_obj.editor( egCore.auth.user().id() );
401                         act_obj.edit_date( new Date() );
402                     } else {
403                         console.log('create');
404                         act_obj.isnew('t');
405                         act_obj.creator( egCore.auth.user().id() );
406                         act_obj.owning_lib( $scope.owningLib );
407                         act_obj.create_date( new Date() );
408                     }
409                     var some_failure = false;
410                     var some_success = false;
411                     egCore.net.request(
412                         'open-ils.cat', // worth replacing with pcrud?
413                         'open-ils.cat.asset.copy_template.create_or_update',
414                         egCore.auth.token(),
415                         act_obj
416                     ).then(
417                         function(resp) {
418                             var evt = egCore.evt.parse(resp);
419                             if (evt) { // any way to just throw or return this to the error handler?
420                                 console.log('failure',resp);
421                                 some_failure = true;
422                                 ngToast.danger(egCore.strings.SERIALS_TEMPLATE_FAIL_SAVE);
423                             } else {
424                                 console.log('success',resp);
425                                 some_success = true;
426                                 ngToast.success(egCore.strings.SERIALS_TEMPLATE_SUCCESS_SAVE);
427                             }
428                         },
429                         function(resp) {
430                             console.log('failure',resp);
431                             some_failure = true;
432                             ngToast.danger(egCore.strings.SERIALS_TEMPLATE_FAIL_SAVE);
433                         }
434                     ).then(function(){
435                         if (some_success && !some_failure) {
436                             //console.log('unsetting dirty for save');
437                             $scope.dirty = false;
438                             $scope.close_modal();
439                         }
440                     });
441                 }
442             
443                 $scope.hashed_template = {};
444                 $scope.imported_template = { data : '' };
445                 $scope.fetchTemplate();
446
447                 // FIXME - leaving this for now
448                 $scope.$watch('imported_template.data', function(newVal, oldVal) {
449                     if (newVal && newVal != oldVal) {
450                         try {
451                             var newTemplate = JSON.parse(newVal);
452                             if (!Object.keys(newTemplate).length) return;
453                             $scope.hashed_template = newTemplate;
454                         } catch (E) {
455                             console.log('tried to import an invalid serials template file');
456                         }
457                     }
458                 });
459
460                 $scope.orgById = function (id) { return egCore.org.get(id) }
461                 $scope.statusById = function (id) {
462                     return $scope.status_list.filter( function (s) { return s.id() == id } )[0];
463                 }
464                 $scope.locationById = function (id) {
465                     return $scope.location_cache[''+id];
466                 }
467             
468                 createSimpleUpdateWatcher = function (field) {
469                     $scope.$watch('working.' + field, function () {
470                         var newval = $scope.working[field];
471             
472                         if (typeof newval != 'undefined') {
473                             //console.log('setting dirty for field',field);
474                             $scope.dirty = true;
475                             if (angular.isObject(newval)) { // we'll use the pkey
476                                 if (newval.id) $scope.working[field] = newval.id();
477                                 else if (newval.code) $scope.working[field] = newval.code();
478                             }
479             
480                             if (""+newval == "" || newval == null) {
481                                 $scope.working[field] = undefined;
482                             }
483             
484                         }
485                     });
486                 }
487
488                 $scope.clearWorking = function () {
489                     angular.forEach($scope.working, function (v,k,o) {
490                         if (!angular.isObject(v)) {
491                             if (typeof v != 'undefined')
492                                 $scope.working[k] = undefined;
493                         } else if (k != 'circ_lib') {
494                             angular.forEach(v, function (sv,sk) {
495                                 $scope.working[k][sk] = undefined;
496                             });
497                         }
498                     });
499                     $scope.working.circ_lib = undefined; // special
500                     $scope.working.loan_duration = 2;
501                     $scope.working.fine_level    = 2;
502                     //console.log('unsetting dirty for clearWorking');
503                     $scope.dirty = false;
504                 }
505
506                 $scope.working = {
507                     loan_duration : 2,
508                     fine_level    : 2
509                 };
510                 $scope.location_orgs = [];
511                 $scope.location_cache = {};
512
513                 $scope.i18n = egCore.i18n;
514                 $scope.location_list = [];
515                 itemSvc.get_locations(
516                     egCore.org.fullPath( egCore.auth.user().ws_ou(), true )
517                 ).then(function(list){
518                     $scope.location_list = list;
519                 });
520                 createSimpleUpdateWatcher('location');
521
522                 $scope.status_list = [];
523                 itemSvc.get_statuses().then(function(list){
524                     $scope.status_list = list;
525                 });
526                 createSimpleUpdateWatcher('status');
527             
528                 $scope.circ_modifier_list = [];
529                 itemSvc.get_circ_mods().then(function(list){
530                     $scope.circ_modifier_list = list;
531                 });
532                 createSimpleUpdateWatcher('circ_modifier');
533             
534                 $scope.circ_type_list = [];
535                 itemSvc.get_circ_types().then(function(list){
536                     $scope.circ_type_list = list;
537                 });
538                 createSimpleUpdateWatcher('circ_as_type');
539             
540                 $scope.age_protect_list = [];
541                 itemSvc.get_age_protects().then(function(list){
542                     $scope.age_protect_list = list;
543                 });
544                 createSimpleUpdateWatcher('age_protect');
545             
546                 createSimpleUpdateWatcher('circulate');
547                 createSimpleUpdateWatcher('holdable');
548
549                 $scope.loan_duration_options = [
550                     {
551                         v: function(){return 1;},
552                         l: function(){return egCore.strings.LOAN_DURATION_SHORT;}
553                     },
554                     {
555                         v: function(){return 2;},
556                         l: function(){return egCore.strings.LOAN_DURATION_NORMAL;}
557                     },
558                     {
559                         v: function(){return 3;},
560                         l: function(){return egCore.strings.LOAN_DURATION_EXTENDED;}
561                     }
562                 ];
563                 createSimpleUpdateWatcher('loan_duration');
564
565                 $scope.fine_level_options = [
566                     {
567                         v: function(){return 1;},
568                         l: function(){return egCore.strings.FINE_LEVEL_LOW;}
569                     },
570                     {
571                         v: function(){return 2;},
572                         l: function(){return egCore.strings.FINE_LEVEL_NORMAL;}
573                     },
574                     {
575                         v: function(){return 3;},
576                         l: function(){return egCore.strings.FINE_LEVEL_HIGH;}
577                     }
578                 ];
579                 createSimpleUpdateWatcher('fine_level');
580
581                 createSimpleUpdateWatcher('name');
582                 createSimpleUpdateWatcher('price');
583                 createSimpleUpdateWatcher('deposit');
584                 createSimpleUpdateWatcher('deposit_amount');
585                 createSimpleUpdateWatcher('mint_condition');
586                 createSimpleUpdateWatcher('opac_visible');
587                 createSimpleUpdateWatcher('ref');
588             }
589         ]
590     }
591 })
592
593