]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/services/fm_record_editor.js
Docs: incorporating offline circ docs
[Evergreen.git] / Open-ILS / web / js / ui / default / staff / services / fm_record_editor.js
1 angular.module('egFmRecordEditorMod',
2     ['egCoreMod', 'egUiMod', 'ui.bootstrap'])
3
4 .directive('egEditFmRecord', function() {
5     return {
6         restrict : 'AE',
7         transclude : true,
8         scope : {
9             // IDL class hint (e.g. "aou")
10             idlClass : '@',
11
12             // mode: 'create' for creating a new record,
13             //       'update' for editing an existing record
14             mode : '@',
15
16             // record ID to update
17             recordId : '=',
18
19             // fields with custom templates
20             // hash keyed on field name; may contain
21             //   template - Angular template; should access
22             //              field value using rec_flat[field.name]
23             //   handlers - any functions you want to pass
24             //              in to the custom template
25             customFieldTemplates : '=?',
26
27             // comma-separated list of fields that should not be
28             // displayed
29             hiddenFields : '@',
30
31             // comma-separated list of fields that should always
32             // be read-only
33             readonlyFields : '@',
34
35             // comma-separated list of required fields; this
36             // supplements what the IDL considers required
37             requiredFields : '@',
38
39             // comma-separated list of org_unit fields where
40             // the selector should default to the workstation OU
41             orgDefaultAllowed : '@',
42
43             // hash, keyed by field name, of functions to invoke
44             // to check whether a field is required.  Each
45             // callback is passed the field name and the record
46             // and should return a boolean value. This supports
47             // cases where whether a field is required or not
48             // depends on the current value of another field.
49             isRequiredOverride : '@',
50
51             // reference to handler to run upon saving
52             // record. The handler will be passed the
53             // record ID and a parameter indicating whether
54             // the save did a create or an update. Note that
55             // even if the mode of the egEditFmRecord is
56             // 'create', the onSave handler may still get
57             // 'update' if the user is permitted to create a
58             // record, then update it
59             onSave : '=',
60
61             // reference to handler to run if the user
62             // cancels the dialog
63             onCancel : '='
64
65         },
66
67         templateUrl : '/eg/staff/share/t_fm_record_editor',
68
69         controller : [
70                     '$scope','egCore',
71             function($scope , egCore) {
72
73             function list_to_hash(str) {
74                 var hash = {};
75                 if (angular.isString(str)) {
76                     str.split(/,/).map(function(s) {
77                         hash[s.trim()] = true;
78                     });
79                 }
80                 return hash;
81             }
82
83             $scope.required = list_to_hash($scope.requiredFields);
84             $scope.readonly = list_to_hash($scope.readonlyFields);
85             $scope.hidden = list_to_hash($scope.hiddenFields);
86             $scope.org_default_allowed = list_to_hash($scope.orgDefaultAllowed);
87
88             $scope.record_label = egCore.idl.classes[$scope.idlClass].label;
89             $scope.rec_orgs = {};
90             $scope.rec_flat = {};
91             $scope.rec_org_values = {};
92             $scope.id_is_editable = false;
93
94             if ($scope.mode == 'update') {
95                 egCore.pcrud.retrieve($scope.idlClass, $scope.recordId).then(function(r) {
96                     $scope.rec = r;
97                     convert_datatypes_to_js($scope.rec);
98                     $scope.fields = get_field_list();
99                 });
100             } else {
101                 if (!('pkey_sequence' in egCore.idl.classes[$scope.idlClass])) {
102                     $scope.id_is_editable = true;
103                 }
104                 $scope.rec = new egCore.idl[$scope.idlClass]();
105                 $scope.fields = get_field_list();
106             }
107
108             function convert_datatypes_to_js(rec) {
109                 var fields = egCore.idl.classes[$scope.idlClass].fields;
110                 angular.forEach(fields, function(field) {
111                     if (field.datatype == 'bool') {
112                         if (rec[field.name]() == 't') {
113                             rec[field.name](true);
114                         } else if (rec[field.name]() == 'f') {
115                             rec[field.name](false);
116                         }
117                     }
118                 });
119             }
120
121             function convert_datatypes_to_idl(rec) {
122                 var fields = egCore.idl.classes[$scope.idlClass].fields;
123                 angular.forEach(fields, function(field) {
124                     if (field.datatype == 'bool') {
125                         if (rec[field.name]() == true) {
126                             rec[field.name]('t');
127                         } else if (rec[field.name]() == false) {
128                             rec[field.name]('f');
129                         }
130                     }
131                     // retrieve values from any fields controlled
132                     // by custom templates, which for the moment all
133                     // expect to be passed an ordinary flat value
134                     if (field.name in $scope.rec_flat) {
135                         rec[field.name]($scope.rec_flat[field.name]);
136                     }
137                 });
138             }
139
140             function flatten_linked_values(cls, list) {
141                 var results = [];
142                 var fields = egCore.idl.classes[cls].fields;
143                 var id_field;
144                 var selector;
145                 angular.forEach(fields, function(fld) {
146                     if (fld.datatype == 'id') {
147                         id_field = fld.name;
148                         selector = fld.selector ? fld.selector : id_field;
149                         return;
150                     }
151                 });
152                 angular.forEach(list, function(item) {
153                     var rec = egCore.idl.toHash(item);
154                     results.push({
155                         id : rec[id_field],
156                         name : rec[selector]
157                     });
158                 });
159                 return results;
160             }
161
162             function get_field_list() {
163                 var fields = egCore.idl.classes[$scope.idlClass].fields;
164
165                 angular.forEach(fields, function(field) {
166                     field.readonly = (field.name in $scope.readonly);
167                     if (angular.isObject($scope.isRequiredOverride) &&
168                         field.name in $scope.isRequiredOverride) {
169                         field.is_required = function() {
170                             return $scope.isRequiredOverride[field.name](field.name, $scope.rec);
171                         }
172                     } else {
173                         field.is_required = function() {
174                             return field.required || (field.name in $scope.required);
175                         }
176                     }
177                     if (field.datatype == 'link') {
178                     egCore.pcrud.retrieveAll(
179                             field.class, {}, {atomic : true}
180                         ).then(function(list) {
181                             field.linked_values = flatten_linked_values(field.class, list);
182                         });
183                     }
184                     if (field.datatype == 'org_unit') {
185                         $scope.rec_orgs[field.name] = function(org) {
186                             if (arguments.length == 1) $scope.rec[field.name](org.id());
187                             return egCore.org.get($scope.rec[field.name]());
188                         }
189                         if ($scope.rec[field.name]()) {
190                             $scope.rec_org_values[field.name] = $scope.rec_orgs[field.name]();
191                         }
192                         field.org_default_allowed = (field.name in $scope.org_default_allowed);
193                     }
194                     if (angular.isObject($scope.customFieldTemplates) && (field.name in $scope.customFieldTemplates)) {
195                         field.use_custom_template = true;
196                         field.custom_template = $scope.customFieldTemplates[field.name].template;
197                         field.handlers = $scope.customFieldTemplates[field.name].handlers;
198                         $scope.rec_flat[field.name] = $scope.rec[field.name]();
199                     }
200                 });
201                 return fields.filter(function(field) { return !(field.name in $scope.hidden) });
202             }
203
204             $scope.ok = function($event) {
205                 var recToSave = egCore.idl.Clone($scope.rec)
206                 convert_datatypes_to_idl(recToSave);
207                 if ($scope.mode == 'update') {
208                     egCore.pcrud.update(recToSave).then(function() {
209                         $scope.onSave($event);
210                     });
211                 } else {
212                     egCore.pcrud.create(recToSave).then(function() {
213                         $scope.onSave($event);
214                     });
215                 }
216             }
217             $scope.cancel = function($event) {
218                 $scope.onCancel($event);
219             }
220         }]
221     };
222 })
223
224 .directive('egFmCustomFieldInput', function($compile) {
225     return {
226         restrict : 'E',
227         scope : {
228             template : '=',
229             handlers : '='
230         },
231         link : function(scope, element, attrs) {
232             element.html(scope.template);
233             $compile(element.contents())(scope.$parent);
234         }
235     };
236 })