/// Now start assembling the normal sub-modules ///
-addNames('YCollection', require('Y/types/collection'));
-addNames('YArray', require('Y/types/array'));
-addNames('YObject deepcopy', require('Y/types/object'));
-addNames('YString', require('Y/types/string'));
-addNames('YNumber range', require('Y/types/number'));
+addNames('YCollection', require('Y/types/collection'));
+addNames('YArray', require('Y/types/array'));
+addNames('YObject getNested setNested deepcopy',
+ require('Y/types/object'));
+addNames('YString', require('Y/types/string'));
+addNames('YNumber range', require('Y/types/number'));
var utils = require('Y/utils');
Y['bindAll'] = utils.bindAll;
var Y = require('Y').Y
-, getNested = require('Y/types/object').getNested
+, getNested = Y.getNested
, Emitter = require('Y/modules/y.event').Emitter
,
*/
updateOnChange : function updateOnChange(events, obj){
if ( !Y.isArray(events) )
- events = events.split();
+ events = events.split(/\s+/);
events = events.map(function events(key){
obj[key.split('.').pop()] = this.get(key);
if ( !Y(key).startsWith('set:') )
addEventListener : function addEventListener(evts, fn){
fn = fn.toFunction();
if ( !Y.isArray(evts) )
- evts = evts.split();
+ evts = evts.split(/\s+/);
evts.forEach(function addEvent(evt){
this.getQueue(evt).push(fn);
}, this);
return evt;
},
- // XXX: does not handle degenerate or recursive event dispatch
+ /**
+ * Dispatches the given event to all listeners in the appropriate queue.
+ * Listeners are invoked with the event, and with context set to the target.
+ * XXX: does not handle degenerate or recursive event dispatch
+ */
dispatchEvent : function dispatchEvent(evt){
this.getQueue(evt.type).invoke('call', evt.target, evt);
if (this.parent) this.parent.fire(evt.type, evt.trigger, evt.data);
,
+// addTypeSupport =
+// exports['addTypeSupport'] =
+// function addTypeSupport(type, parser, builder){
+// var T = Y.typeName(type);
+// type2parser[T] = parser;
+// }
+// ,
+
Field =
exports['Field'] =
this.key = chain.split('.').pop();
this.label = camelToSpaces(this.key);
- var T = Y(Y.type(val)).getName();
+ var T = Y.typeName(def);
this.cast = options.cast || type2parser[T];
this.type = options.type || type2el[T];
},
function createField(group, value, chain){
var def = config.getDefault(chain)
- , field = new Field(chain, def, value);
+ , T = Y.typeName(def);
+
+ if (!type2parser[T])
+ return group;
+ var field = new Field(chain, def, value);
fields[chain] = field;
group.append(field.el);
config.addEventListener('set:'+chain, function onConfigSet(evt){
"Boolean Number String Function Array Date RegExp Object"
.split(" ")
.reduce(function(class2name, name) {
- class2name[ "[object "+name+"]" ] = name.toLowerCase();
+ class2name[ "[object "+name+"]" ] = name;
return class2name;
}, {});
-function type_of(obj){
- return obj == null ?
- String( obj ) :
- class2name[ toString.call(obj) ] || "object";
+function basicTypeName(o){
+ return o == null ?
+ String(o) :
+ class2name[ toString.call(o) ] || "Object";
+}
+
+function typeName(o){
+ if (o === undefined || o === null)
+ return String(o);
+ var T = type(o);
+ return T.className || (T !== Function ? T.name : basicTypeName(o));
}
var arrayLike = isArray.types = [];
-function isArray(obj) { return type_of(obj) === "array" || (arrayLike.indexOf(type(obj)) !== -1); }
-function isFunction(obj) { return type_of(obj) === "function"; }
-function isString(obj) { return type_of(obj) === "string"; }
-function isNumber(obj) { return type_of(obj) === "number"; }
-function isWindow(obj) { return obj && typeof obj === "object" && "setInterval" in obj; }
+function isArray(o) { return basicTypeName(o) === "Array" || (arrayLike.indexOf(type(o)) !== -1); }
+function isFunction(o) { return basicTypeName(o) === "Function"; }
+function isString(o) { return basicTypeName(o) === "String"; }
+function isNumber(o) { return basicTypeName(o) === "Number"; }
+function isWindow(o) { return o && typeof o === "object" && "setInterval" in o; }
-function isPlainObject( obj ){
+function isPlainObject(o){
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
- if ( !obj || type_of(obj) !== "object" || obj.nodeType || isWindow(obj) )
+ if ( !o || basicTypeName(o) !== "Object" || o.nodeType || isWindow(o) )
return false;
// Not own constructor property must be Object
- if ( obj[FN] &&
- !hasOwn.call(obj, FN) &&
- !hasOwn.call(obj[FN][PT], "isPrototypeOf") )
+ if ( o[FN] &&
+ !hasOwn.call(o, FN) &&
+ !hasOwn.call(o[FN][PT], "isPrototypeOf") )
return false;
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
- for ( key in obj ) {}
+ for ( key in o ) {}
- return key === undefined || hasOwn.call( obj, key );
+ return key === undefined || hasOwn.call( o, key );
}
-function type( o ) {
+function type(o) {
if ( o === null || o === undefined )
return o;
}
}
-function is( A, B ){
+function is(A, B){
if ( isArray(B) )
return B.some( is.bind(this,A) );
else {
exports['is'] = is;
exports['type'] = type;
-exports['type_of'] = type_of;
+exports['basicTypeName'] = basicTypeName;
+exports['typeName'] = typeName;
exports['isArray'] = isArray;
exports['isFunction'] = isFunction;
exports['isWindow'] = isWindow;
exports['isPlainObject'] = isPlainObject;
-type['KNOWN_CLASSES'] = KNOWN_CLASSES;
+type['KNOWN_CLASSES'] = KNOWN_CLASSES;
// Export these last to avoid methodizing them
exports['YFunction'] = YF(YF);
-exports._ = _;
+exports['_'] = _;
}
// Do we have a type-specific wrapper?
- var name = type.type_of(o)
- , yname = 'Y' + name.charAt(0).toUpperCase() + name.slice(1)
+ var yname = 'Y' + type.basicTypeName(o)
, YType = Y[yname]
;
, objToString = _Object[P].toString
, classToString = function toString(){ return this.className+"()"; }
-;
+,
+
-// Private delegating constructor -- must be defined for every
-// new class to prevent shared state. All construction is
-// actually done in the init method.
-exports['ConstructorTemplate'] = ConstructorTemplate;
+/**
+ * @private
+ * Private delegating constructor. This function must be redefined for every
+ * new class to prevent shared state. All construction is actually done in
+ * the methods initialise and init.
+ *
+ * Fires `create` event prior to initialisation if not subclassing.
+ */
+ConstructorTemplate =
+exports['ConstructorTemplate'] =
function ConstructorTemplate() {
var cls = arguments.callee
, instance = this;
return instance;
}
+,
+/**
+ * Fires `init` event after calling init(). Note that events are fired
+ * for proper instances of the class and instances of subclasses (but
+ * not for the instance created when subclassing).
+ */
+createInitialise =
+exports['createInitialise'] =
+function createInitialise(NewClass){
+ function initialise(){
+ var instance = this
+ , init = NewClass.prototype.init
+ ;
+
+ instance.__emitter__ = new Emitter(instance, NewClass);
+
+ if (init) {
+ var result = init.apply(instance, arguments);
+ if (result) instance = result;
+ }
+
+ instance.fire('init', instance, {
+ 'instance' : instance,
+ 'cls' : NewClass,
+ 'args' : Y(arguments)
+ });
+
+ return instance;
+ }
+ return Y(initialise);
+}
+;
NewClass.__super__ = SuperClass; // don't override NewClass.constructor -- it should be Function
prototype.constructor = prototype.__class__ = NewClass;
- NewClass.init = // XXX: This means subclasses will fire events.
- prototype.initialise =
- Y(function initialise(){
- var instance = this
- , init = NewClass.prototype.init
- ;
-
- instance.__emitter__ = new Emitter(instance, NewClass);
-
- if (init) {
- var result = init.apply(instance, arguments);
- if (result) instance = result;
- }
-
- instance.fire('init', instance, {
- 'instance' : instance,
- 'cls' : NewClass,
- 'args' : Y(arguments)
- });
-
- return instance;
- });
+ NewClass.init = prototype.initialise = createInitialise(NewClass);
// Add class emitter
var ParentEmitter = (Parent.__emitter__ ? Parent : ClassFactory)
_cssClasses : 'ezl layer',
canvas : null,
-
parent : null,
children : null,
// Transforms
_origin : null, // rotational origin
transform : null, // Object
- useCanvasScaling : false, // default to CSS3 scaling
/// Defaults ///
+ useCanvasScaling : false, // Default to CSS3 scaling
+ alwaysClearDrawing : true, // Whether to clear the canvas content before redraw
+ alwaysClearAttrs : false, // Whether to remove all canvas attributes (CONTEXT_ATTRS)
+ // and transforms (scale, rotate, translate) and reset defaults before redraw
+
originX : 0,
originY : 0,
*/
empty : function empty(ctx){
this.children.invoke('remove');
- this.clear();
+ this.clear(ctx);
return this;
},
* @param {Boolean} [force=false] Forces redraw.
*/
draw : function draw(ctx, force){
+ var _ctx = ctx || this.ctx;
+
if ( this.dirty || force ){
- var _ctx = ctx || this.ctx;
+ this.dirty = false;
this._openPath(_ctx);
- this.drawShape(_ctx);
+ this.render(_ctx);
this._closePath(_ctx);
}
- this.dirty = false;
this.children.invoke('draw', ctx, force);
return this;
},
_openPath : function _openPath(ctx){
var self = this
- , alwaysClear = this.alwaysClear
, neg = this.negBleed
, t = this.transform
, w = this.canvasWidth, h = this.canvasHeight ;
ctx.beginPath();
- ctx.setTransform(1,0,0,1,0,0);
- ctx.clearRect(-w,-h, 2*w,2*h);
+ // TODO: only alwaysClearAttrs should reset transforms?
+ // if (this.alwaysClearAttrs)
+ ctx.setTransform(1,0,0,1,0,0);
+
+ if (this.alwaysClearDrawing)
+ ctx.clearRect(-w,-h, 2*w,2*h);
+
+ // if (this.alwaysClearAttrs) {
if (this.useCanvasScaling && (t.scale.x !== 1 || t.scale.y !== 1))
ctx.scale(t.scale.x,t.scale.y);
ctx.translate(neg.x, neg.y);
ctx.translate(t.translate.x, t.translate.y);
+ // }
// Set context attributes
CONTEXT_ATTRS.forEach(function(name){
- if (self[name] !== undefined)
- ctx[name] = self[name];
- else if (alwaysClear)
+ if (this[name] !== undefined)
+ ctx[name] = this[name];
+ else if (this.alwaysClearAttrs)
delete ctx[name];
- });
+ }, this);
return this;
},
/** To be implemented by subclasses. */
- drawShape : function drawShape(ctx){ return this; },
+ render : function render(ctx){ return this; },
_closePath : function _closePath(ctx){
ctx.closePath();
},
/**
- * Clears this layer and all children.
+ * Clears this layer and optionally all children.
*/
- clear : function clear(ctx){
+ clear : function clear(ctx, clearChildren){
var w = this.canvas.width()
, h = this.canvas.height();
ctx = ctx || this.ctx;
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(-w,-h, 2*w,2*h);
ctx.closePath();
- this.children.invoke('clear');
+ if (clearChildren)
+ this.children.invoke('clear');
return this;
},