]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/staff/services/fm_record_editor.js
LP#1736269: Mark Missing Pieces is non-functional
[working/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 id_field = egCore.idl.classes[cls].pkey;
143                 var selector = egCore.idl.classes[cls].field_map[id_field].selector || id_field;
144                 angular.forEach(list, function(item) {
145                     results.push({
146                         id : item[id_field](),
147                         name : item[selector]()
148                     });
149                 });
150                 return results;
151             }
152
153             function get_field_list() {
154                 var fields = egCore.idl.classes[$scope.idlClass].fields;
155
156                 angular.forEach(fields, function(field) {
157                     field.readonly = (field.name in $scope.readonly);
158                     if (angular.isObject($scope.isRequiredOverride) &&
159                         field.name in $scope.isRequiredOverride) {
160                         field.is_required = function() {
161                             return $scope.isRequiredOverride[field.name](field.name, $scope.rec);
162                         }
163                     } else {
164                         field.is_required = function() {
165                             return field.required || (field.name in $scope.required);
166                         }
167                     }
168                     if (field.datatype == 'link') {
169                         egCore.pcrud.retrieveAll(
170                             field.class, {}, {atomic : true}
171                         ).then(function(list) {
172                             field.linked_values = flatten_linked_values(field.class, list);
173                         });
174                     }
175                     if (field.datatype == 'org_unit') {
176                         $scope.rec_orgs[field.name] = function(org) {
177                             if (arguments.length == 1) $scope.rec[field.name](org.id());
178                             return egCore.org.get($scope.rec[field.name]());
179                         }
180                         if ($scope.rec[field.name]()) {
181                             $scope.rec_org_values[field.name] = $scope.rec_orgs[field.name]();
182                         }
183                         field.org_default_allowed = (field.name in $scope.org_default_allowed);
184                     }
185                     if (angular.isObject($scope.customFieldTemplates) && (field.name in $scope.customFieldTemplates)) {
186                         field.use_custom_template = true;
187                         field.custom_template = $scope.customFieldTemplates[field.name].template;
188                         field.handlers = $scope.customFieldTemplates[field.name].handlers;
189                         $scope.rec_flat[field.name] = $scope.rec[field.name]();
190                     }
191                 });
192                 return fields.filter(function(field) { return !(field.name in $scope.hidden) });
193             }
194
195             $scope.ok = function($event) {
196                 var recToSave = egCore.idl.Clone($scope.rec)
197                 convert_datatypes_to_idl(recToSave);
198                 if ($scope.mode == 'update') {
199                     egCore.pcrud.update(recToSave).then(function() {
200                         $scope.onSave($event);
201                     });
202                 } else {
203                     egCore.pcrud.create(recToSave).then(function() {
204                         $scope.onSave($event);
205                     });
206                 }
207             }
208             $scope.cancel = function($event) {
209                 $scope.onCancel($event);
210             }
211         }]
212     };
213 })
214
215 .directive('egFmCustomFieldInput', function($compile) {
216     return {
217         restrict : 'E',
218         scope : {
219             template : '=',
220             handlers : '='
221         },
222         link : function(scope, element, attrs) {
223             element.html(scope.template);
224             $compile(element.contents())(scope.$parent);
225         }
226     };
227 })