Created
February 23, 2013 07:33
-
-
Save kampfer/5018839 to your computer and use it in GitHub Desktop.
Composition Pattern In JavaScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
kampfer.require('events.EventTarget'); | |
kampfer.provide('Composition'); | |
kampfer.Composition = kampfer.events.EventTarget.extend({ | |
_id : null, | |
_parent : null, | |
//array | |
//_children必须与_childrenIndex同步 | |
//懒加载 | |
_children : null, | |
//object | |
//_childrenIndex必须与_children同步 | |
//懒加载 | |
_childrenIndex : null, | |
//递归调用子节点的指定方法 | |
//实现composition模式的关键方法之一 | |
walk : function(method) { | |
var args = Array.prototype.slice.apply(arguments, 1); | |
this.forEachChild(function(child, i) { | |
if( kampfer.type(child[method]) === 'function' ) { | |
child[method].apply(child, args); | |
} | |
}); | |
}, | |
getId : function() { | |
return this._id || | |
( this._id = kampfer.UIComponent.generateUniqueId() ); | |
}, | |
setId : function(id) { | |
if(this._parent && this._parent._childrenIndex) { | |
delete this._parent._childrenIndex[this._id]; | |
this._parent._childrenIndex[id] = this; | |
} | |
this._id = id; | |
}, | |
getParent : function() { | |
return this._parent; | |
}, | |
setParent : function(parent) { | |
//新的parent不为空时,必须是component实例 | |
if( parent && !(parent instanceof kampfer.UIComponent) ) { | |
return; | |
} | |
//新的parent不能是对象自己 | |
if(parent === this) { | |
return; | |
} | |
//对象已经是另一个对象的child,那么必须先调用removeChild之后再调用setParent | |
//对象不可能同时是另外两个对象的child | |
if( parent && this._parent && this._id && | |
this._parent.getChild(this._id) && parent !== this._parent ) { | |
return; | |
} | |
this._parent = parent; | |
this.setParentEventTarget(parent); | |
//对象不是新parent的child,那么将child添加到parnet的子列表中 | |
//因为addchild方法会检查_parent属性,所以必须在设置完_parent属性后才能执行添加操作 | |
//closure没有这一步, 它的setParent方法只保证child的parent属性正确, | |
//但不保证child一定在parnet的子节点列表中 | |
if( parent && !parent.getChild(this._id) ) { | |
parent.addChild(this); | |
} | |
}, | |
addChild : function(child, render) { | |
this.addChildAt(child, this.getChildCount(), render); | |
}, | |
addChildAt : function(child, index, render) { | |
if( !(child instanceof kampfer.UIComponent) ) { | |
return; | |
} | |
if(index < 0 || index > this.getChildCount() ) { | |
return; | |
} | |
if(!this._children || !this._childrenIndex) { | |
this._children = []; | |
this._childrenIndex = {}; | |
} | |
if( child.getParent() === this ) { | |
//删除_children中保存的child引用 | |
//避免_children中保存多个child引用 | |
for(var i = 0, c; (c = this._children[i]); i++) { | |
if(c === child) { | |
this._children.splice(i, 1); | |
} | |
} | |
} | |
this._childrenIndex[child.getId()] = child; | |
this._children.splice(index, 0, child); | |
//closure没有这一步, 它的addChildAt方法只保证child在parent的子节点列表中, | |
//不保证child的parent一定是this. 这里我尝试增加这种确定性. | |
if(child._parent !== this) { | |
child.setParent(this); | |
} | |
}, | |
getChild : function(id) { | |
if(id && this._childrenIndex) { | |
return this._childrenIndex[id]; | |
} | |
}, | |
getChildAt : function(index) { | |
if(this._children) { | |
return this._children[index]; | |
} | |
}, | |
removeChild : function(child) { | |
if(child) { | |
var id; | |
if( kampfer.type(child) === 'string' ) { | |
id = child; | |
child = this.getChild(id); | |
} else { | |
id = child.getId(); | |
} | |
for(var i = 0, c; (c = this._children[i]); i++) { | |
if(c === child) { | |
this._children.splice(i, 1); | |
} | |
} | |
delete this._childrenIndex[id]; | |
child.setParent(null); | |
} | |
return child; | |
}, | |
removeChildAt : function(index, unrender) { | |
this.remochild( this.getChildAt(index), unrender ); | |
}, | |
forEachChild : function(callback, context) { | |
for(var i = 0, child; (child = this._children[i]); i++) { | |
if( calllback.call(context || child, child, i) === false ) { | |
return; | |
} | |
} | |
}, | |
indexOfChild : function(child) { | |
this.forEachChild(function(c, i) { | |
if(c === child) { | |
return i; | |
} | |
}); | |
}, | |
getChildCount : function() { | |
if(this._children) { | |
return this._children.length; | |
} | |
}, | |
dispose : function() { | |
kampfer.Composition.superClass.dispose.call(this); | |
delete this._parent; | |
delete this._children; | |
delete this._childrenIndex; | |
} | |
}); | |
kampfer.Composition.generateUniqueId = function() { | |
var guid = ""; | |
for(var i = 1; i <= 32; i++) { | |
var n = Math.floor(Math.random() * 16.0).toString(16); | |
guid += n; | |
if((i == 8) || (i == 12) || (i == 16) || (i == 20)) { | |
guid += "-"; | |
} | |
} | |
return guid; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment