6 * var aou = new egIDL.aou();
7 * var fullIDL = egIDL.classes;
11 * 1. selector field only appears once per class. We could save
12 * a lot of IDL (network) space storing it only once at the
14 * 2. we don't need to store array_position in /IDL2js since it
15 * can be derived at parse time. Ditto saving space.
17 angular.module('egCoreMod')
19 .factory('egIDL', ['$window', function($window) {
23 // Clones data structures containing fieldmapper objects
24 service.Clone = function(old) {
26 if (typeof old == 'undefined') {
28 } else if (old._isfieldmapper) {
29 obj = new service[old.classname]()
31 for( var i in old.a ) {
33 if(thing === null) continue;
35 if (typeof thing == 'undefined') {
37 } else if (thing._isfieldmapper) {
38 obj.a[i] = service.Clone(thing);
41 if(angular.isArray(thing)) {
44 for( var j in thing ) {
46 if (typeof thing[j] == 'undefined')
47 obj.a[i][j] = thing[j];
48 else if( thing[j]._isfieldmapper )
49 obj.a[i][j] = service.Clone(thing[j]);
51 obj.a[i][j] = angular.copy(thing[j]);
54 obj.a[i] = angular.copy(thing);
59 if(angular.isArray(old)) {
62 if (typeof old[j] == 'undefined')
64 else if( old[j]._isfieldmapper )
65 obj[j] = service.Clone(old[j]);
67 obj[j] = angular.copy(old[j]);
69 } else if(angular.isObject(old)) {
72 if (typeof old[j] == 'undefined')
74 else if( old[j]._isfieldmapper )
75 obj[j] = service.Clone(old[j]);
77 obj[j] = angular.copy(old[j]);
80 obj = angular.copy(old);
86 service.parseIDL = function() {
87 //console.debug('egIDL.parseIDL()');
89 // retain a copy of the full IDL within the service
90 service.classes = $window._preload_fieldmapper_IDL;
92 // keep this reference around (note: not a clone, just a ref)
93 // so that unit tests, which repeatedly instantiate the
95 //$window._preload_fieldmapper_IDL = null;
98 * Creates the class constructor and getter/setter
99 * methods for each IDL class.
101 function mkclass(cls, fields) {
103 service.classes[cls].core_label = service.classes[cls].core ? 'Core sources' : 'Non-core sources';
104 service.classes[cls].classname = cls;
106 service[cls] = function(seed) {
108 this.classname = cls;
109 this._isfieldmapper = true;
112 /** creates the getter/setter methods for each field */
113 angular.forEach(fields, function(field, idx) {
114 service[cls].prototype[fields[idx].name] = function(n) {
115 if (arguments.length==1) this.a[idx] = n;
120 // global class constructors required for JSON_v1.js
121 $window[cls] = service[cls];
124 for (var cls in service.classes)
125 mkclass(cls, service.classes[cls].fields);
129 * Generate a hash version of an IDL object.
131 * Flatten determines if nested objects should be squashed into
132 * the top-level hash.
134 * If 'flatten' is false, e.g.:
136 * {"call_number" : {"label" : "foo"}}
138 * If 'flatten' is true, e.g.:
140 * e.g. {"call_number.label" : "foo"}
142 service.toHash = function(obj, flatten) {
143 if (!angular.isObject(obj)) return obj; // arrays are objects
145 if (angular.isArray(obj)) { // NOTE: flatten arrays not supported
146 return obj.map(function(item) {return service.toHash(item)});
149 var field_names = obj.classname ?
150 Object.keys(service.classes[obj.classname].field_map) :
158 var val = service.toHash(
159 angular.isFunction(obj[field]) ?
160 obj[field]() : obj[field],
164 if (flatten && angular.isObject(val)) {
165 angular.forEach(val, function(sub_val, key) {
166 var fname = field + '.' + key;
167 hash[fname] = sub_val;
170 } else if (val !== undefined) {
179 // returns a simple string key=value string of an IDL object.
180 service.toString = function(obj) {
183 service.classes[obj.classname].fields.sort(
184 function(a,b) {return a.name < b.name ? -1 : 1}),
186 s += field.name + '=' + obj[field.name]() + '\n';
192 // hash-to-IDL object translater. Does not support nested values.
193 service.fromHash = function(cls, hash) {
194 if (!service.classes[cls]) {
195 console.error('No such IDL class ' + cls);
199 var new_obj = new service[cls]();
200 angular.forEach(hash, function(val, key) {
201 if (!angular.isFunction(new_obj[key])) return;
202 new_obj[key](hash[key]);
208 // Transforms a flattened hash (see toHash() or egGridFlatDataProvider)
211 // e.g. {"call_number.label" : "foo"} => {"call_number":{"label":"foo"}}
212 service.flatToNestedHash = function(obj) {
214 angular.forEach(obj, function(val, key) {
215 var parts = key.split('.');
218 for (var i = 0; i < parts.length; i++) {
220 if (i == parts.length - 1) {
221 sub_hash[part] = val;
226 sub_hash = sub_hash[part];
234 // Using IDL links, allow construction of a tree-ish data structure from
235 // the IDL2js web service output. This structure will be directly usable
236 // by the <treecontrol> directive
237 service.classTree = {
241 function _sort_class_fields (a,b) {
242 var aname = a.label || a.name;
243 var bname = b.label || b.name;
244 return aname > bname ? 1 : -1;
247 service.classTree.buildNode = function (cls, args) {
248 if (!cls) return null;
250 var n = service.classes[cls];
254 args = { label : n.label };
258 args.id = args.from + '.' + args.id;
260 return angular.extend( args, {
267 fields : n.fields.sort( _sort_class_fields ),
269 .filter( function(x) { return x.type == 'link'; } )
270 .sort( _sort_class_fields ),
275 service.classTree.fleshNode = function ( node ) {
276 if (node.children.length > 0)
277 return node; // already done already
280 node.links.sort( _sort_class_fields ),
282 var nlabel = n.label ? n.label : n.name;
284 service.classTree.buildNode(
298 service.classTree.setTop = function (cls) {
299 console.debug('setTop: '+cls);
300 return service.classTree.top = service.classTree.fleshNode(
301 service.classTree.buildNode(cls)
305 service.classTree.getTop = function () {
306 return service.classTree.top;