diff options
author | Petr Vobornik <pvoborni@redhat.com> | 2013-04-05 18:38:02 +0200 |
---|---|---|
committer | Petr Vobornik <pvoborni@redhat.com> | 2013-05-06 16:22:23 +0200 |
commit | abdb5455d1954f2fab4d5def42c6b99590067eae (patch) | |
tree | 213fe89364b7a363ec3a3df11c47e163761cafa6 | |
parent | 03d3742376739aaa28b142b81d757ffeee2ed4ce (diff) | |
download | freeipa-abdb5455d1954f2fab4d5def42c6b99590067eae.tar.gz freeipa-abdb5455d1954f2fab4d5def42c6b99590067eae.tar.xz freeipa-abdb5455d1954f2fab4d5def42c6b99590067eae.zip |
Add pre and post build operations
https://fedorahosted.org/freeipa/ticket/3235
-rw-r--r-- | install/ui/src/freeipa/_base/Builder.js | 76 | ||||
-rw-r--r-- | install/ui/src/freeipa/_base/Construct_registry.js | 125 | ||||
-rw-r--r-- | install/ui/src/freeipa/_base/construct.js | 20 |
3 files changed, 190 insertions, 31 deletions
diff --git a/install/ui/src/freeipa/_base/Builder.js b/install/ui/src/freeipa/_base/Builder.js index d7503526b..10c544cce 100644 --- a/install/ui/src/freeipa/_base/Builder.js +++ b/install/ui/src/freeipa/_base/Builder.js @@ -41,17 +41,19 @@ define(['dojo/_base/declare', /** * Build object based on spec. * - * @param spec {String|Function|Object} Build spec + * @param {String|Function|Object} Build spec * * String: type name, queries registry * Function: factory or constructor * Object: spec object * * Build control properies of spec object: - * constructor: Function - * factory: Function - * mixim_spec: Boolean - * type: String + * $constructor: Function + * $factory: Function + * $mixim_spec: Boolean + * $type: String + * $pre_ops: [] + * $post_ops: [] * * All other properties will be passed to object construction method. */ @@ -78,16 +80,20 @@ define(['dojo/_base/declare', // spec is type name cs = this._query_registry(spec); } else if (typeof spec === 'object') { - var c = spec.constructor, - f = spec.factory, - m = spec.mixim_spec, - t = spec.type; + var c = spec.$constructor, + f = spec.$factory, + m = spec.$mixim_spec, + t = spec.$type, + pre = spec.$pre_ops, + post = spec.$post_ops; var s = lang.clone(spec); - delete s.constructor; - delete s.factory; - delete s.mixim_spec; - delete s.type; + delete s.$constructor; + delete s.$factory; + delete s.$mixim_spec; + delete s.$type; + delete s.$pre_ops; + delete s.$post_ops; if (c) { cs.constructor = c; @@ -105,19 +111,30 @@ define(['dojo/_base/declare', cs.spec = s; } } + + cs.pre_ops = cs.pre_ops || []; + cs.post_ops = cs.post_ops || []; + if (pre) cs.pre_ops.push.call(cs.pre_ops, pre); + if (pre) cs.post_ops.push.call(cs.post_ops, post); } return cs; }, + /** + * Queries registry and returns copy of construction specification + */ _query_registry: function(type) { if (this.registry) { - return this.registry.get(type); + var cs = this.registry.get(type); + if (!cs) throw construct.no_cs_for_type_error(type); + cs = construct.copy_cs(cs); + return cs; } else { throw { error: 'Build error: construct registry required', - spec: type + builder: this }; } }, @@ -125,7 +142,22 @@ define(['dojo/_base/declare', _build: function(construction_spec) { var cs = construction_spec, - obj = null; + obj = null, + i; + + if (cs.pre_ops) { + for (i=0; i<cs.pre_ops.length; i++) { + var preop = cs.pre_ops[i]; + var preop_t = typeof preop; + if (preop_t === 'function') { + cs.spec = preop(cs.spec || {}); + } else if (preop_t === 'object') { + lang.mixin(cs.spec, preop); + } + } + } + + cs.spec = cs.spec || {}; if (cs.factory && typeof cs.factory === 'function') { obj = cs.factory(cs.spec); @@ -138,6 +170,18 @@ define(['dojo/_base/declare', }; } + if (cs.post_ops && obj) { + for (i=0; i<cs.post_ops.length; i++) { + var postop = cs.post_ops[i]; + var postop_t = typeof postop; + if (postop_t === 'function') { + obj = postop(obj); + } else if (postop_t === 'object') { + lang.mixin(obj, postop); + } + } + } + return obj; }, diff --git a/install/ui/src/freeipa/_base/Construct_registry.js b/install/ui/src/freeipa/_base/Construct_registry.js index 82f0f617e..a49f2d583 100644 --- a/install/ui/src/freeipa/_base/Construct_registry.js +++ b/install/ui/src/freeipa/_base/Construct_registry.js @@ -50,10 +50,12 @@ define(['dojo/_base/declare', * * May be defined by single construction spec object: * var construction_spec = { - * type: string, - * factory: function, - * constructor: function, - * spec: object + * type: String, + * factory: Function, + * constructor: Function, + * spec: Object, + * pre_ops: [], + * post_ops: [] * }; * register(construction_spec); * @@ -62,13 +64,13 @@ define(['dojo/_base/declare', */ register: function(type, func, default_spec) { - var spec, f, c; + var cs, f, c; if (typeof type === 'object') { - spec = type; + cs = type; } else { construct.is_constructor(func) ? c = func : f = func; - spec = { + cs = { type: type, factory: f, constructor: c, @@ -76,16 +78,87 @@ define(['dojo/_base/declare', }; } - if (typeof spec.type !== 'string' || spec.type !== '') { - throw 'Argument exception: Invalid type'; - } - if (typeof spec.factory !== 'function' && - typeof spec.constructor !== 'function') { - throw 'Argument exception: No factory or constructor defined'; + if (!cs.pre_ops) cs.pre_ops = []; + if (!cs.post_ops) cs.post_ops = []; + + this._check_spec(cs); + + this._map[cs.type] = cs; + return cs; + }, + + /** + * Makes a copy of construct specification of original type. Extends + * it with values in supplied construct specification. + * + * @param {String} Original type + * @param {String} New type + * @param {Object} Construction specification + */ + copy: function(org_type, new_type, construct_spec) { + + var def_cs = construct_spec; + var old_cs = this._check_get(org_type); + var cs = construct.copy_cs(old_cs); + + cs.type = new_type; + if (def_cs.pre_ops) cs.pre_ops.push.call(cs.pre_ops, def_cs.pre_ops); + if (def_cs.post_ops) cs.post_ops.push.call(cs.post_ops, def_cs.post_ops); + if (def_cs.factory) cs.factory = def_cs.factory; + if (def_cs.constructor) cs.constructor = def_cs.constructor; + if (def_cs.spec) { + cs.spec = cs.spec || {}; + lang.mixin(cs.spec, def_cs.spec); } - this._map[spec.type] = spec; - return spec; + this._check_spec(cs); + + this._map[cs.type] = cs; + return cs; + }, + + /** + * Registers pre operation. + * + * Purpose of pre operation is to modify spec object before build + * operation. + * + * When op is Function it gets called with spec as a param and should + * return modified spec. + * + * When op is Object, the object gets mixed in into spec. + * + * @param {type} type + * @param {Function|Object} op + * @param {Boolean} move op to first position + */ + register_pre_op: function(type, op, first) { + + var cs = this._check_get(type); + if (first) cs.pre_ops.unshift(op); + else cs.pre_ops.push(op); + }, + + /** + * Registers post operation. + * + * Purpose of post operation is to modify built object. + * + * When op is Function it gets called with built object as a param + * and should return modified obj. + * + * When op is Object, the object gets mixed in into built object. Use + * with caution. + * + * @param {type} type + * @param {Function|Object} op + * @param {Boolean} move op to first position + */ + register_post_op: function(type, op, first) { + + var cs = this._check_get(type); + if (first) cs.post_ops.unshift(op); + else cs.post_ops.push(op); }, /** @@ -96,6 +169,28 @@ define(['dojo/_base/declare', */ get: function(type) { return this._map[type] || null; + }, + + _check_get: function(type) { + var cs = this.get(type); + if (!cs) throw construct.no_cs_for_type_error(type); + return cs; + }, + + _check_spec: function(spec) { + if (typeof spec.type !== 'string' || spec.type === '') { + throw 'Argument exception: Invalid type'; + } + if (typeof spec.factory !== 'function' && + typeof spec.constructor !== 'function') { + throw 'Argument exception: No factory or constructor defined'; + } + if (!lang.isArrayLike(spec.pre_ops)) { + throw 'Argument exception: Invalid pre_ops type.'; + } + if (!lang.isArrayLike(spec.post_ops)) { + throw 'Argument exception: Invalid post_ops type.'; + } } }); diff --git a/install/ui/src/freeipa/_base/construct.js b/install/ui/src/freeipa/_base/construct.js index 77a5e1726..91e5a0bb2 100644 --- a/install/ui/src/freeipa/_base/construct.js +++ b/install/ui/src/freeipa/_base/construct.js @@ -37,6 +37,26 @@ define(['dojo/_base/declare', // TODO: Find better method. Check by extend might not be very // reliable. return typeof obj === 'function' && typeof obj.extend === 'function'; + }, + + /** + * Creates copy of construction specification + * + * It makes sure that pre_ops, post_ops and spec are new Arrays/Object + */ + copy_cs: function(org_cs) { + var cs = lang.clone(org_cs); + if (cs.spec) cs.spec = lang.clone(cs.spec); + cs.pre_ops = cs.pre_ops.slice(0); + cs.post_ops = cs.pre_ops.slice(0); + return cs; + }, + + no_cs_for_type_error: function(type) { + return { + error: 'No construction specification for given type', + type: type + }; } }; return construct; |