1 /** 2 * @constructor 3 */ 4 var YNode = function(value){ 5 this.value = typeof(value!='undefined')?value:null; 6 this.parent = null; 7 this.childs = []; 8 }; 9 YNode.prototype = { 10 constructor : YNode, 11 constructorName : "YNode", 12 // -------------------------- basic use 13 getRoot :function(){ 14 if(this.parent) return this.parent.getRoot(); 15 else return this; 16 }, 17 getValue :function(){ 18 //alert(this instanceof this.constructor); 19 return this.value; 20 }, 21 setValue :function(value){ 22 this.value = value; 23 }, 24 hasIndex :function(index){ 25 return index>=0 && index<this.childs.length && index%1==0; 26 }, 27 getDepth :function(){ 28 var node = this; 29 var depth=0; 30 while(node.parent){ depth++; node=node.parent; } 31 return depth; 32 }, 33 getIndex :function(){ 34 if(this.parent) return this.parent.getChildIndex(this); 35 else return -1; 36 }, 37 getChildIndex :function(ynode){ 38 if(ynode instanceof this.constructor){ 39 for(var i=0;i<this.childs.length;i++){ 40 if(ynode==this.childs[i])return i; 41 } 42 return -1; 43 }else throw("\n"+this.constructorName+".getChildIndex Error :\n ynode must be an instance of '"+this.constructorName+"'"); 44 }, 45 addChilds :function(ynodeList){ 46 for(var i in ynodeList){ 47 this.addChild(ynodeList[i]); 48 } 49 }, 50 addChild :function(ynode){ 51 if(ynode instanceof this.constructor){ 52 ynode.parent = this; 53 this.childs.push(ynode); 54 return this.childs.length-1; 55 }else throw("\n"+this.constructorName+".addChild Error :\n ynode must be an instance of '"+this.constructorName+"'."); 56 }, 57 addChildAt :function(ynode,index){ 58 if(ynode instanceof this.constructor){ 59 if(index>=0 && index<this.childs.length){ 60 this.childs.splice(index,0,ynode); 61 }else this.childs.push(ynode); 62 ynode.parent = this; 63 }else throw("\n"+this.constructorName+".addChildAt Error :\n ynode must be an instance of '"+this.constructorName+"'."); 64 }, 65 /** 66 add ynode before this one in his parent list. 67 @param {YNode} ynode the new and previous node. 68 */ 69 addPrev :function(ynode){ 70 if(this.parent){ 71 this.parent.addChildAt(ynode,this.getIndex()); 72 }else throw("\n"+this.constructorName+".addNext Error:\nynode have no parent."); 73 }, 74 /** 75 add ynode after this one in his parent list. 76 @param {YNode} ynode the new and next node. 77 */ 78 addNext :function(ynode){ 79 if(this.parent){ 80 this.parent.addChildAt(ynode,this.getIndex()+1); 81 }else throw("\n"+this.constructorName+".addNext Error:\nynode have no parent."); 82 }, 83 /** 84 remove child at 'index'. 85 @param {int} index removed node index. 86 @return {YNode} the removed node and childs. 87 */ 88 removeChildAt :function(index){ 89 if(this.hasIndex(index)){ 90 var node = this.childs[index]; 91 this.childs[index].parent = null; 92 this.childs.splice(index,1); 93 return node; 94 }else throw("\n"+this.constructorName+".removeChildAt Error:\nindex="+index+" out of range[0->"+(this.childs.length-1)+"]."); 95 }, 96 /** 97 remove every node childs. 98 @return {YNode[]} removed nodes list. 99 */ 100 removeAll :function(){ 101 var list = this.chids; 102 this.chids = []; 103 for(var i in list){ list[i].parent = null;} 104 return list; 105 }, 106 /** 107 exchange node but keep replaced node childs. 108 @param {YNode} ynode new node. 109 @param {int} index replaced node index. 110 @return {YNode} the replaced node with the new node childs. 111 */ 112 substitute :function(ynode,index){ 113 if(this.hasIndex(index)){ 114 var tmp = this.exchange(ynode,index); 115 var list = tmp.removeAll(); 116 var list2 = ynode.removeAll(); 117 ynode.addChilds(list); 118 tmp.addChilds(list2); 119 }else throw("\n"+this.constructorName+".substitute Error:\nindex="+index+" out of range[0->"+(this.childs.length-1)+"]."); 120 }, 121 /** 122 exchange node and childs. 123 @param {YNode} ynode new node. 124 @param {int} index replaced node index. 125 @return {YNode} the replaced node and childs. 126 */ 127 exchange :function(ynode,index){ 128 if(this.hasIndex(index)){ 129 var tmp = this.removeChildAt(index); 130 this.addChildAt(ynode,index); 131 return tmp; 132 }else throw("\n"+this.constructorName+".exchange Error:\nindex="+index+" out of range[0->"+(this.childs.length-1)+"]."); 133 }, 134 removeChild :function(ynode){ 135 var ci = this.getChildIndex(ynode); 136 if(ci==-1)throw("\n"+this.constructorName+".removeChild Error:\nynode object not found."); 137 return this.removeChildAt(ci); 138 }, 139 removeMe :function(){ 140 if(this.parent) return this.parent.removeChild(this); 141 else return null; 142 }, 143 swapChild :function(indexA,indexB){ 144 if(this.hasIndex(indexA)&&this.hasIndex(indexB)&&indexA==indexB){ 145 var tmp = this.childs[indexA]; 146 this.childs[indexA]=this.childs[indexB]; 147 this.childs[indexB]=tmp; 148 return true; 149 }else return false; 150 }, 151 getPath :function(){ 152 var puf = function(node,datas){return node.getIndex(); }; 153 var res = this.parseUp(puf,null); 154 res.shift(); 155 return res; 156 }, 157 // -------------------------- parsing 158 parseUp :function(Function,datas){ 159 var p_pup = function(node,Function,datas,result){ 160 result.unshift(Function(node,datas)); 161 if(node.parent){ p_pup(node.parent,Function,datas,result); } 162 return result; 163 }; 164 return p_pup(this,Function,datas,[]); 165 }, 166 parseChilds :function(Function,datas){ 167 var res = []; 168 for(var i=0;i<this.childs.length;i++){ 169 res.push(Function(this.childs[i],datas)); 170 }return res; 171 }, 172 parseBA :function(FunctionBefore,FunctionAfter,datas){ 173 var pparse = function(node,before,after,datas,parentResult){ 174 if(datas && datas.parseStop)return parentResult; 175 var res = {childs:[],datas:null}; 176 if(typeof(before)=="function"){ 177 res.before = before(node,datas,parentResult); 178 res.datas = res.before; 179 } 180 for(var i=0;i<node.childs.length;i++){ 181 pparse(node.childs[i],before,after,datas,res); 182 } 183 if(typeof(after)=="function"){ 184 res.after = after(node,datas,parentResult); 185 res.datas = res.before; 186 } 187 parentResult.childs.push(res); 188 return parentResult; 189 }; 190 return pparse(this,FunctionBefore,FunctionAfter,datas,{childs:[],datas:null}).childs[0]; 191 }, 192 findAll :function(Function,datas){ 193 var obj = {found:[],funk:Function,dataz:datas}; 194 this.parse(function(node,obj){ 195 if(obj.funk(node,obj.dataz)){ obj.found.push( node); } 196 },obj); 197 return obj.found; 198 }, 199 find :function(Function,datas){ 200 var obj = {found:null,funk:Function,dataz:datas}; 201 this.parse(function(node,obj){ 202 if(obj.funk(node,obj.dataz)){ obj.found = node; obj.parseStop = true; } 203 },obj); 204 return obj.found; 205 }, 206 parse :function(Function,datas){ 207 return this.parseBA(Function,null,datas); 208 }, 209 parseFromLeafs :function(Function,datas){ 210 return this.parseBA(null,Function,datas); 211 }, 212 parseResultToNode :function(presult){ 213 if(presult&&typeof(presult.datas)!='undefined'){ 214 var node = new YNode(presult.datas); 215 if(presult.childs){ 216 for(var i=0;i<presult.childs.length;i++){ 217 node.addChild(this.parseResultToNode(presult.childs[i])); 218 } 219 }return node; 220 }return null; 221 } 222 }; 223 /* 224 // how to extend : 225 var YNodeEx=function(value){ 226 YNode.call(this); 227 this.value = value; 228 }; 229 YNodeEx.prototype = new YNode(); 230 YNodeEx.prototype.constructor = YNodeEx; 231 YNodeEx.prototype.constructorName = 'YNodeEx'; 232 */