summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Vobornik <pvoborni@redhat.com>2013-04-05 18:38:02 +0200
committerPetr Vobornik <pvoborni@redhat.com>2013-05-06 16:22:23 +0200
commitabdb5455d1954f2fab4d5def42c6b99590067eae (patch)
tree213fe89364b7a363ec3a3df11c47e163761cafa6
parent03d3742376739aaa28b142b81d757ffeee2ed4ce (diff)
downloadfreeipa-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.js76
-rw-r--r--install/ui/src/freeipa/_base/Construct_registry.js125
-rw-r--r--install/ui/src/freeipa/_base/construct.js20
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;