LP#1708291: teach egIDL a new fieldmapper object representation
authorGalen Charlton <gmc@equinoxinitiative.org>
Fri, 21 Apr 2017 16:05:45 +0000 (12:05 -0400)
committerDan Wells <dbw2@calvin.edu>
Fri, 1 Sep 2017 16:47:01 +0000 (12:47 -0400)
This patch teaches egIDL how to represent fieldmapper objects
as objects with attributes rather than getter/setters. This
allows FM objects to be more easily bound to common to Angular
input widgets, avoiding the verbosity of getterSetter ng-options
and the fact that some widgets like uib-datepicker-popup don't
support getterSetter in the first place.

Usage is:

  hash = obj.toTypedHash()

and

  obj = new egCore.idl.fromTypedHash(hash);

Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Signed-off-by: Dan Wells <dbw2@calvin.edu>
Open-ILS/web/js/ui/default/staff/services/idl.js

index 29b7989..629e595 100644 (file)
@@ -144,6 +144,67 @@ angular.module('egCoreMod')
         return hash;
     }
 
+    service.toTypedHash = function(obj) {
+        if (!angular.isObject(obj)) return obj; // arrays are objects
+
+        if (angular.isArray(obj)) { // NOTE: flatten arrays not supported
+            return obj.map(function(item) {return service.toTypedHash(item)});
+        }
+
+        var field_names = obj.classname ? 
+            Object.keys(service.classes[obj.classname].field_map) :
+            Object.keys(obj);
+
+        var hash = {};
+        if (obj.classname) {
+            angular.extend(hash, {
+                _classname : obj.classname
+            });
+        }
+        angular.forEach(
+            field_names,
+            function(field) { 
+
+                var val = service.toTypedHash(
+                    angular.isFunction(obj[field]) ? 
+                        obj[field]() : obj[field]
+                );
+
+                if (val !== undefined) {
+                    if (obj.classname) {
+                        switch(service.classes[obj.classname].field_map[field].datatype) {
+                            case 'org_unit' :
+                                // aou fieldmapper objects get used as is because
+                                // that's what egOrgSelector expects
+                                // TODO we should probably make egOrgSelector more flexible
+                                //      in what it can bind to
+                                hash[field] = obj[field]();
+                                break;
+                            case 'timestamp':
+                                hash[field] = (val === null) ? val : new Date(val);
+                                break;
+                            case 'bool':
+                                if (val == 't') {
+                                    hash[field] = true;
+                                } else if (val == 'f') {
+                                    hash[field] = false;
+                                } else {
+                                    hash[field] = null;
+                                }
+                                break;
+                            default:
+                                hash[field] = val;
+                        }
+                    } else {
+                        hash[field] = val;
+                    }
+                }
+            }
+        );
+
+        return hash;
+    }
+
     // returns a simple string key=value string of an IDL object.
     service.toString = function(obj) {
         var s = '';
@@ -173,6 +234,46 @@ angular.module('egCoreMod')
         return new_obj;
     }
 
+    service.fromTypedHash = function(hash) {
+        if (!angular.isObject(hash)) return hash;
+        if (angular.isArray(hash)) {
+            return hash.map(function(item) {return service.fromTypedHash(item)});
+        }
+        if (!hash._classname) return;
+
+        var new_obj = new service[hash._classname];
+        var fields = service.classes[hash._classname].field_map;
+        angular.forEach(fields, function(field) {
+            switch(field.datatype) {
+                case 'org_unit':
+                    if (angular.isFunction(hash[field.name])) {
+                        new_obj[field.name] = hash[field.name];
+                    } else {
+                        new_obj[field.name](hash[field.name]);
+                    }
+                    break;
+                case 'timestamp':
+                    if (hash[field.name] instanceof Date) {
+                        new_obj[field.name](hash[field.name].toISOString());
+                    }
+                    break;
+                case 'bool':
+                    if (hash[field.name] === true) {
+                        new_obj[field.name]('t');
+                    } else if (hash[field.name] === false) {
+                        new_obj[field.name]('f');
+                    }
+                    break;
+                default:
+                    new_obj[field.name](service.fromTypedHash(hash[field.name]));
+            }
+        });
+        new_obj.isnew(hash._isnew);
+        new_obj.ischanged(hash._ischanged);
+        new_obj.isdeleted(hash._isdeleted);
+        return new_obj;
+    }
+
     // Transforms a flattened hash (see toHash() or egGridFlatDataProvider)
     // to a nested hash.
     //