summaryrefslogtreecommitdiff
path: root/frontend/beta/js/YUI-extensions/tree
Unidiff
Diffstat (limited to 'frontend/beta/js/YUI-extensions/tree') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js58
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeDragZone.js43
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeDropZone.js228
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeFilter.js105
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeLoader.js107
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeNode.js300
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js452
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreePanel.js213
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js195
-rw-r--r--frontend/beta/js/YUI-extensions/tree/TreeSorter.js49
10 files changed, 1750 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js b/frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js
new file mode 100644
index 0000000..5d48b00
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/AsyncTreeNode.js
@@ -0,0 +1,58 @@
1YAHOO.ext.tree.AsyncTreeNode = function(config){
2 this.loaded = false;
3 this.loading = false;
4 YAHOO.ext.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
5 this.events['beforeload'] = true;
6 this.events['load'] = true;
7};
8YAHOO.extendX(YAHOO.ext.tree.AsyncTreeNode, YAHOO.ext.tree.TreeNode, {
9 expand : function(deep, anim, callback){
10 if(this.loading){ // if an async load is already running, waiting til it's done
11 var timer;
12 var f = function(){
13 if(!this.loading){ // done loading
14 clearInterval(timer);
15 this.expand(deep, anim, callback);
16 }
17 }.createDelegate(this);
18 timer = setInterval(f, 200);
19 }
20 if(!this.loaded){
21 if(this.fireEvent('beforeload', this) === false){
22 return;
23 }
24 this.loading = true;
25 this.ui.beforeLoad(this);
26 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
27 if(loader){
28 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
29 return;
30 }
31 }
32 YAHOO.ext.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33 },
34
35 isLoading : function(){
36 return this.loading;
37 },
38
39 loadComplete : function(deep, anim, callback){
40 this.loading = false;
41 this.loaded = true;
42 this.ui.afterLoad(this);
43 this.fireEvent('load', this);
44 this.expand(deep, anim, callback);
45 },
46
47 isLoaded : function(){
48 return this.loaded;
49 },
50
51 hasChildNodes : function(){
52 if(!this.isLeaf() && !this.loaded){
53 return true;
54 }else{
55 return YAHOO.ext.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
56 }
57 }
58});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeDragZone.js b/frontend/beta/js/YUI-extensions/tree/TreeDragZone.js
new file mode 100644
index 0000000..9b77b3c
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeDragZone.js
@@ -0,0 +1,43 @@
1YAHOO.ext.tree.TreeDragZone = function(tree, config){
2 YAHOO.ext.tree.TreeDragZone.superclass.constructor.call(this, tree.getEl(), config);
3 this.tree = tree;
4};
5
6YAHOO.extendX(YAHOO.ext.tree.TreeDragZone, YAHOO.ext.dd.DragZone, {
7 ddGroup : 'TreeDD',
8
9 onBeforeDrag : function(data, e){
10 var n = data.node;
11 return n && n.draggable && !n.disabled;
12 },
13
14 onInitDrag : function(e){
15 var data = this.dragData;
16 this.tree.getSelectionModel().select(data.node);
17 this.proxy.update('');
18 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
19 this.tree.fireEvent('startdrag', this.tree, data.node, e);
20 },
21
22 getRepairXY : function(e, data){
23 return data.node.ui.getDDRepairXY();
24 },
25
26 onEndDrag : function(data, e){
27 this.tree.fireEvent('enddrag', this.tree, data.node, e);
28 },
29
30 onValidDrop : function(dd, e, id){
31 this.tree.fireEvent('dragdrop', this.tree, this.dragData.node, dd, e);
32 this.hideProxy();
33 },
34
35 beforeInvalidDrop : function(e, id){
36 if(YAHOO.util.Anim){
37 // this scrolls the original position back into view
38 var sm = this.tree.getSelectionModel();
39 sm.clearSelections();
40 sm.select(this.dragData.node);
41 }
42 }
43});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeDropZone.js b/frontend/beta/js/YUI-extensions/tree/TreeDropZone.js
new file mode 100644
index 0000000..91c24e1
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeDropZone.js
@@ -0,0 +1,228 @@
1YAHOO.ext.tree.TreeDropZone = function(tree, config){
2 this.allowParentInsert = false;
3 this.allowContainerDrop = false;
4 this.appendOnly = false;
5 YAHOO.ext.tree.TreeDropZone.superclass.constructor.call(this, tree.container, config);
6 this.tree = tree;
7 this.lastInsertClass = 'ytree-no-status';
8 this.dragOverData = {};
9};
10
11YAHOO.extendX(YAHOO.ext.tree.TreeDropZone, YAHOO.ext.dd.DropZone, {
12 ddGroup : 'TreeDD',
13
14 expandDelay : 1000,
15
16 expandNode : function(node){
17 if(node.hasChildNodes() && !node.isExpanded()){
18 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
19 }
20 },
21
22 queueExpand : function(node){
23 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
24 },
25
26 cancelExpand : function(){
27 if(this.expandProcId){
28 clearTimeout(this.expandProcId);
29 this.expandProcId = false;
30 }
31 },
32
33 isValidDropPoint : function(n, pt, dd, e, data){
34 if(!n || !data){ return false; }
35 var targetNode = n.node;
36 var dropNode = data.node;
37 // default drop rules
38 if(!(targetNode && targetNode.isTarget && pt)){
39 return false;
40 }
41 if(pt == 'append' && targetNode.allowChildren === false){
42 return false;
43 }
44 if((pt == 'above' || pt == 'below') && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
45 return false;
46 }
47 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
48 return false;
49 }
50 // reuse the object
51 var overEvent = this.dragOverData;
52 overEvent.tree = this.tree;
53 overEvent.target = targetNode;
54 overEvent.data = data;
55 overEvent.point = pt;
56 overEvent.source = dd;
57 overEvent.rawEvent = e;
58 overEvent.dropNode = dropNode;
59 overEvent.cancel = false;
60 var result = this.tree.fireEvent('nodedragover', overEvent);
61 return overEvent.cancel === false && result !== false;
62 },
63
64 getDropPoint : function(e, n, dd){
65 var tn = n.node;
66 if(tn.isRoot){
67 return tn.allowChildren !== false ? 'ap-pend' : false; // always append for root
68 }
69 var dragEl = n.ddel;
70 var t = YAHOO.util.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
71 var y = YAHOO.util.Event.getPageY(e);
72 var noAppend = tn.allowChildren === false || tn.isLeaf();
73 if(this.appendOnly || tn.parentNode.allowChildren === false){
74 return noAppend ? false : 'append';
75 }
76 var noBelow = false;
77 if(!this.allowParentInsert){
78 noBelow = tn.hasChildNodes() && tn.isExpanded();
79 }
80 var q = (b - t) / (noAppend ? 2 : 3);
81 if(y >= t && y < t + q){
82 return 'above';
83 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
84 return 'below';
85 }else{
86 return 'append';
87 }
88 return false;
89 },
90
91 onNodeEnter : function(n, dd, e, data){
92 this.cancelExpand();
93 },
94
95 onNodeOver : function(n, dd, e, data){
96 var pt = this.getDropPoint(e, n, dd);
97 var node = n.node;
98
99 // auto node expand check
100 if(!this.expandProcId && pt == 'append' && node.hasChildNodes() && !n.node.isExpanded()){
101 this.queueExpand(node);
102 }else if(pt != 'append'){
103 this.cancelExpand();
104 }
105
106 // set the insert point style on the target node
107 var returnCls = this.dropNotAllowed;
108 if(this.isValidDropPoint(n, pt, dd, e, data)){
109 if(pt){
110 var el = n.ddel;
111 var cls, returnCls;
112 if(pt == 'above'){
113 returnCls = n.node.isFirst() ? 'ytree-drop-ok-above' : 'ytree-drop-ok-between';
114 cls = 'ytree-drag-insert-above';
115 }else if(pt == 'below'){
116 returnCls = n.node.isLast() ? 'ytree-drop-ok-below' : 'ytree-drop-ok-between';
117 cls = 'ytree-drag-insert-below';
118 }else{
119 returnCls = 'ytree-drop-ok-append';
120 cls = 'ytree-drag-append';
121 }
122 if(this.lastInsertClass != cls){
123 YAHOO.util.Dom.replaceClass(el, this.lastInsertClass, cls);
124 this.lastInsertClass = cls;
125 }
126 }
127 }
128 return returnCls;
129 },
130
131 onNodeOut : function(n, dd, e, data){
132 this.cancelExpand();
133 this.removeDropIndicators(n);
134 },
135
136 onNodeDrop : function(n, dd, e, data){
137 var point = this.getDropPoint(e, n, dd);
138 var targetNode = n.node;
139 targetNode.ui.startDrop();
140 if(!this.isValidDropPoint(n, point, dd, e, data)){
141 targetNode.ui.endDrop();
142 return false;
143 }
144 // first try to find the drop node
145 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
146 var dropEvent = {
147 tree : this.tree,
148 target: targetNode,
149 data: data,
150 point: point,
151 source: dd,
152 rawEvent: e,
153 dropNode: dropNode,
154 cancel: dropNode ? false : true
155 };
156 var retval = this.tree.fireEvent('beforenodedrop', dropEvent);
157 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
158 targetNode.ui.endDrop();
159 return false;
160 }
161 if(point == 'append' && !targetNode.isExpanded()){
162 targetNode.expand(false, null, function(){
163 this.completeDrop(dropEvent);
164 }.createDelegate(this));
165 }else{
166 this.completeDrop(dropEvent);
167 }
168 return true;
169 },
170
171 completeDrop : function(de){
172 var ns = de.dropNode, p = de.point, t = de.target;
173 if(!(ns instanceof Array)){
174 ns = [ns];
175 }
176 var n;
177 for(var i = 0, len = ns.length; i < len; i++){
178 n = ns[i];
179 if(p == 'above'){
180 t.parentNode.insertBefore(n, t);
181 }else if(p == 'below'){
182 t.parentNode.insertBefore(n, t.nextSibling);
183 }else{
184 t.appendChild(n);
185 }
186 }
187 n.select(); // select and highlight the last insert
188 if(this.tree.hlDrop){
189 n.ui.highlight();
190 }
191 t.ui.endDrop();
192 this.tree.fireEvent('nodedrop', de);
193 },
194
195 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
196 if(this.tree.hlDrop){
197 dropNode.select();
198 dropNode.ui.highlight();
199 }
200 this.tree.fireEvent('nodedrop', this.tree, targetNode, data, dd, e);
201 },
202
203 getTree : function(){
204 return this.tree;
205 },
206
207 removeDropIndicators : function(n){
208 if(n && n.ddel){
209 var el = n.ddel;
210 YAHOO.util.Dom.removeClass(el, 'ytree-drag-insert-above');
211 YAHOO.util.Dom.removeClass(el, 'ytree-drag-insert-below');
212 YAHOO.util.Dom.removeClass(el, 'ytree-drag-append');
213 this.lastInsertClass = '_noclass';
214 }
215 },
216
217 beforeDragDrop : function(target, e, id){
218 this.cancelExpand();
219 return true;
220 },
221
222 afterRepair : function(data){
223 if(data){
224 data.node.ui.highlight();
225 }
226 this.hideProxy();
227 }
228});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeFilter.js b/frontend/beta/js/YUI-extensions/tree/TreeFilter.js
new file mode 100644
index 0000000..9eeb274
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeFilter.js
@@ -0,0 +1,105 @@
1/**
2 * This doesn't update the indent (lines) or expand collapse icons of the nodes
3 */
4YAHOO.ext.tree.TreeFilter = function(tree, config){
5 this.tree = tree;
6 this.filtered = {};
7 YAHOO.ext.util.Config.apply(this, config, {
8 clearBlank:false,
9 reverse:false,
10 autoClear:false,
11 remove:false
12 });
13};
14
15YAHOO.ext.tree.TreeFilter.prototype = {
16 /**
17 * Filter the data by a specific attribute.
18 * @param {String/RegExp} value Either string that the attribute value
19 * should start with or a RegExp to test against the attribute
20 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
21 * @param {TreeNode} startNode (optional) The node to start the filter at.
22 */
23 filter : function(value, attr, startNode){
24 attr = attr || 'text';
25 var f;
26 if(typeof value == 'string'){
27 var vlen = value.length;
28 // auto clear empty filter
29 if(vlen == 0 && this.clearBlank){
30 this.clearFilter();
31 return;
32 }
33 value = value.toLowerCase();
34 f = function(n){
35 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36 }
37 }else if(value.exec){ // regex?
38 f = function(n){
39 return value.test(n.attributes[attr]);
40 }
41 }else{
42 throw 'Illegal filter type, must be string or regex';
43 }
44 this.filterBy(f, null, startNode);
45 },
46
47 /**
48 * Filter by a function. The passed function will be called with each
49 * node in the tree (or from the startNode). If the function returns true, the node is kept
50 * otherwise it is filtered. If a node is filtered, it's children are also filtered.
51 * @param {Function} fn The filter function
52 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
53 */
54 filterBy : function(fn, scope, startNode){
55 startNode = startNode || this.tree.root;
56 if(this.autoClear){
57 this.clearFilter();
58 }
59 var af = this.filtered, rv = this.reverse;
60 var f = function(n){
61 if(n == startNode){
62 return true;
63 }
64 if(af[n.id]){
65 return false;
66 }
67 var m = fn.call(scope || n, n);
68 if(!m || rv){
69 af[n.id] = n;
70 n.ui.hide();
71 return false;
72 }
73 return true;
74 }
75 startNode.cascade(f);
76 if(this.remove){
77 for(var id in af){
78 if(typeof id != 'function'){
79 var n = af[id];
80 if(n && n.parentNode){
81 n.parentNode.removeChild(n);
82 }
83 }
84 }
85 }
86 },
87
88 /**
89 * Clears the current filter. Note: with the "remove" option
90 * set a filter cannot be cleared.
91 */
92 clear : function(){
93 var t = this.tree;
94 var af = this.filtered;
95 for(var id in af){
96 if(typeof id != 'function'){
97 var n = af[id];
98 if(n){
99 n.ui.show();
100 }
101 }
102 }
103 this.filtered = {};
104 }
105};
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeLoader.js b/frontend/beta/js/YUI-extensions/tree/TreeLoader.js
new file mode 100644
index 0000000..34989bd
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeLoader.js
@@ -0,0 +1,107 @@
1YAHOO.ext.tree.TreeLoader = function(config){
2 this.baseParams = {};
3 this.requestMethod = 'POST';
4 YAHOO.ext.util.Config.apply(this, config);
5
6 this.events = {
7 'beforeload' : true,
8 'load' : true,
9 'loadexception' : true
10 };
11};
12
13YAHOO.extendX(YAHOO.ext.tree.TreeLoader, YAHOO.ext.util.Observable, {
14 load : function(node, callback){
15 if(node.attributes.children){ // preloaded json children
16 var cs = node.attributes.children;
17 for(var i = 0, len = cs.length; i < len; i++){
18 node.appendChild(this.createNode(cs[i]));
19 }
20 if(typeof callback == 'function'){
21 callback();
22 }
23 }else if(this.dataUrl){
24 this.requestData(node, callback);
25 }
26 },
27
28 getParams: function(node){
29 var buf = [], bp = this.baseParams;
30 for(var key in bp){
31 if(typeof bp[key] != 'function'){
32 buf.push(encodeURIComponent(key), '=', encodeURIComponent(bp[key]), '&');
33 }
34 }
35 buf.push('node=', encodeURIComponent(node.id));
36 return buf.join('');
37 },
38
39 requestData : function(node, callback){
40 if(this.fireEvent('beforeload', this, node, callback) !== false){
41 var params = this.getParams(node);
42 var cb = {
43 success: this.handleResponse,
44 failure: this.handleFailure,
45 scope: this,
46 argument: {callback: callback, node: node}
47 };
48 this.transId = YAHOO.util.Connect.asyncRequest(this.requestMethod, this.dataUrl, cb, params);
49 }else{
50 // if the load is cancelled, make sure we notify
51 // the node that we are done
52 if(typeof callback == 'function'){
53 callback();
54 }
55 }
56 },
57
58 isLoading : function(){
59 return this.transId ? true : false;
60 },
61
62 abort : function(){
63 if(this.isLoading()){
64 YAHOO.util.Connect.abort(this.transId);
65 }
66 },
67
68 createNode : function(attr){
69 if(this.applyLoader !== false){
70 attr.loader = this;
71 }
72 return(attr.leaf ?
73 new YAHOO.ext.tree.TreeNode(attr) :
74 new YAHOO.ext.tree.AsyncTreeNode(attr));
75 },
76
77 processResponse : function(response, node, callback){
78 var json = response.responseText;
79 try {
80 var o = eval('('+json+')');
81 for(var i = 0, len = o.length; i < len; i++){
82 node.appendChild(this.createNode(o[i]));
83 }
84 if(typeof callback == 'function'){
85 callback();
86 }
87 }catch(e){
88 this.handleFailure(response);
89 }
90 },
91
92 handleResponse : function(response){
93 this.transId = false;
94 var a = response.argument;
95 this.processResponse(response, a.node, a.callback);
96 this.fireEvent('load', this, a.node, response);
97 },
98
99 handleFailure : function(response){
100 this.transId = false;
101 var a = response.argument;
102 this.fireEvent('loadexception', this, a.node, response);
103 if(typeof a.callback == 'function'){
104 a.callback();
105 }
106 }
107});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeNode.js b/frontend/beta/js/YUI-extensions/tree/TreeNode.js
new file mode 100644
index 0000000..c676481
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeNode.js
@@ -0,0 +1,300 @@
1/**
2 * @class YAHOO.ext.tree.TreeNode
3 * @extends YAHOO.ext.data.Node
4 * @cfg {Boolean} leaf true if this node is a leaf and does not have or cannot have children
5 * @cfg {Boolean} expanded true to start the node expanded
6 * @cfg {Boolean} draggable false to make this node undraggable if DD is on (default to true)
7 * @cfg {Boolean} isTarget false if this node cannot be drop on
8 * @cfg {Boolean} disabled true to start the node disabled
9 * @constructor
10 * @param {Object} attributes The attributes/config for the node
11 */
12YAHOO.ext.tree.TreeNode = function(attributes){
13 attributes = attributes || {};
14 if(typeof attributes == 'string'){
15 attributes = {text: attributes};
16 }
17 this.el = null;
18 this.childrenRendered = false;
19 this.rendered = false;
20 YAHOO.ext.tree.TreeNode.superclass.constructor.call(this, attributes);
21 this.expanded = attributes.expanded === true;
22 this.isTarget = attributes.isTarget !== false;
23 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
24 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
25 this.text = attributes.text;
26 this.disabled = attributes.disabled === true;
27
28 YAHOO.ext.util.Config.apply(this.events, {
29 'textchange' : true,
30 'beforeexpand' : true,
31 'beforecollapse' : true,
32 'expand' : true,
33 'disabledchange' : true,
34 'collapse' : true,
35 'beforeclick':true,
36 'click':true,
37 'dblclick':true,
38 'contentmenu':true,
39 'beforechildrenrendered':true
40 });
41
42 var uiClass = this.attributes.uiProvider || YAHOO.ext.tree.TreeNodeUI;
43 this.ui = new uiClass(this);
44};
45YAHOO.extendX(YAHOO.ext.tree.TreeNode, YAHOO.ext.data.Node, {
46 isExpanded : function(){
47 return this.expanded;
48 },
49
50 getUI : function(){
51 return this.ui;
52 },
53
54 setFirstChild : function(node){
55 var of = this.firstChild;
56 YAHOO.ext.tree.TreeNode.superclass.setFirstChild.call(this, node);
57 if(this.childrenRendered && of && node != of){
58 of.renderIndent(true, true);
59 }
60 if(this.rendered){
61 this.renderIndent(true, true);
62 }
63 },
64
65 setLastChild : function(node){
66 var ol = this.lastChild;
67 YAHOO.ext.tree.TreeNode.superclass.setLastChild.call(this, node);
68 if(this.childrenRendered && ol && node != ol){
69 ol.renderIndent(true, true);
70 }
71 if(this.rendered){
72 this.renderIndent(true, true);
73 }
74 },
75
76 // these methods are overridden to provide lazy rendering support
77 appendChild : function(){
78 var node = YAHOO.ext.tree.TreeNode.superclass.appendChild.apply(this, arguments);
79 if(node && this.childrenRendered){
80 node.render();
81 }
82 this.ui.updateExpandIcon();
83 return node;
84 },
85
86 removeChild : function(node){
87 this.ownerTree.getSelectionModel().unselect(node);
88 YAHOO.ext.tree.TreeNode.superclass.removeChild.apply(this, arguments);
89 // if it's been rendered remove dom node
90 if(this.childrenRendered){
91 node.ui.remove();
92 }
93 if(this.childNodes.length < 1){
94 this.collapse(false, false);
95 }else{
96 this.ui.updateExpandIcon();
97 }
98 return node;
99 },
100
101 insertBefore : function(node, refNode){
102 var newNode = YAHOO.ext.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
103 if(newNode && refNode && this.childrenRendered){
104 node.render();
105 }
106 this.ui.updateExpandIcon();
107 return newNode;
108 },
109
110 setText : function(text){
111 var oldText = this.text;
112 this.text = text;
113 this.attributes.text = text;
114 if(this.rendered){ // event without subscribing
115 this.ui.onTextChange(this, text, oldText);
116 }
117 this.fireEvent('textchange', this, text, oldText);
118 },
119
120 select : function(){
121 this.getOwnerTree().getSelectionModel().select(this);
122 },
123
124 unselect : function(){
125 this.getOwnerTree().getSelectionModel().unselect(this);
126 },
127
128 isSelected : function(){
129 return this.getOwnerTree().getSelectionModel().isSelected(node);
130 },
131
132 expand : function(deep, anim, callback){
133 if(!this.expanded){
134 if(this.fireEvent('beforeexpand', this, deep, anim) === false){
135 return;
136 }
137 if(!this.childrenRendered){
138 this.renderChildren();
139 }
140 this.expanded = true;
141 if((this.getOwnerTree().animate && anim !== false) || anim){
142 this.ui.animExpand(function(){
143 this.fireEvent('expand', this);
144 if(typeof callback == 'function'){
145 callback(this);
146 }
147 if(deep === true){
148 this.expandChildNodes(true);
149 }
150 }.createDelegate(this));
151 return;
152 }else{
153 this.ui.expand();
154 this.fireEvent('expand', this);
155 if(typeof callback == 'function'){
156 callback(this);
157 }
158 }
159 }else{
160 if(typeof callback == 'function'){
161 callback(this);
162 }
163 }
164 if(deep === true){
165 this.expandChildNodes(true);
166 }
167 },
168
169 collapse : function(deep, anim){
170 if(this.expanded && (!this.isRoot || (this.isRoot && this.getOwnerTree().rootVisible))){
171 if(this.fireEvent('beforecollapse', this, deep, anim) === false){
172 return;
173 }
174 this.expanded = false;
175 if((this.getOwnerTree().animate && anim !== false) || anim){
176 this.ui.animCollapse(function(){
177 this.fireEvent('collapse', this);
178 if(deep === true){
179 this.collapseChildNodes(true);
180 }
181 }.createDelegate(this));
182 return;
183 }else{
184 this.ui.collapse();
185 this.fireEvent('collapse', this);
186 }
187 }
188 if(deep === true){
189 var cs = this.childNodes;
190 for(var i = 0, len = cs.length; i < len; i++) {
191 cs[i].collapse(true)
192 }
193 }
194 },
195
196 delayedExpand : function(delay){
197 if(!this.expandProcId){
198 this.expandProcId = this.expand.defer(delay, this);
199 }
200 },
201
202 cancelExpand : function(){
203 if(this.expandProcId){
204 clearTimeout(this.expandProcId);
205 }
206 this.expandProcId = false;
207 },
208
209 toggle : function(){
210 if(this.expanded){
211 this.collapse();
212 }else{
213 this.expand();
214 }
215 },
216
217 ensureVisible : function(){
218 if(this.parentNode){
219 this.parentNode.bubble(function(){
220 this.expand(false, false);
221 });
222 }
223 },
224
225 expandChildNodes : function(deep){
226 var cs = this.childNodes;
227 for(var i = 0, len = cs.length; i < len; i++) {
228 cs[i].expand(deep);
229 }
230 },
231
232 collapseChildNodes : function(deep){
233 var cs = this.childNodes;
234 for(var i = 0, len = cs.length; i < len; i++) {
235 cs[i].expand(deep);
236 }
237 },
238
239 disable : function(){
240 this.disabled = true;
241 this.unselect();
242 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
243 this.ui.onDisableChange(this, true);
244 }
245 this.fireEvent('disabledchange', this, true);
246 },
247
248 enable : function(){
249 this.disabled = false;
250 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
251 this.ui.onDisableChange(this, false);
252 }
253 this.fireEvent('disabledchange', this, false);
254 },
255
256 renderChildren : function(suppressEvent){
257 if(suppressEvent !== false){
258 this.fireEvent('beforechildrenrendered', this);
259 }
260 var cs = this.childNodes;
261 for(var i = 0, len = cs.length; i < len; i++){
262 cs[i].render(true);
263 }
264 this.childrenRendered = true;
265 },
266
267 sort : function(fn, scope){
268 YAHOO.ext.tree.TreeNode.superclass.sort.apply(this, arguments);
269 if(this.childrenRendered){
270 var cs = this.childNodes;
271 for(var i = 0, len = cs.length; i < len; i++){
272 cs[i].render(true);
273 }
274 }
275 },
276
277 render : function(bulkRender){
278 this.ui.render(bulkRender);
279 if(!this.rendered){
280 this.rendered = true;
281 if(this.expanded){
282 this.expanded = false;
283 this.expand(false, false);
284 }
285 }
286 },
287
288 renderIndent : function(deep, refresh){
289 if(refresh){
290 this.ui.childIndent = null;
291 }
292 this.ui.renderIndent();
293 if(deep === true && this.childrenRendered){
294 var cs = this.childNodes;
295 for(var i = 0, len = cs.length; i < len; i++){
296 cs[i].renderIndent(true, refresh);
297 }
298 }
299 }
300});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js b/frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js
new file mode 100644
index 0000000..80927f4
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeNodeUI.js
@@ -0,0 +1,452 @@
1/**
2 * The TreeNode UI implementation is separate from the
3 * tree implementation. Unless you are customizing the tree UI,
4 * you should never have to use this directly.
5 */
6YAHOO.ext.tree.TreeNodeUI = function(node){
7 this.node = node;
8 this.rendered = false;
9 this.animating = false;
10};
11
12YAHOO.ext.tree.TreeNodeUI.prototype = {
13 emptyIcon : Ext.BLANK_IMAGE_URL,
14
15 removeChild : function(node){
16 if(this.rendered){
17 this.ctNode.removeChild(node.ui.getEl());
18 }
19 },
20
21 beforeLoad : function(){
22 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-loading');
23 },
24
25 afterLoad : function(){
26 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-node-loading');
27 },
28
29 onTextChange : function(node, text, oldText){
30 if(this.rendered){
31 this.textNode.innerHTML = text;
32 }
33 },
34
35 onDisableChange : function(node, state){
36 this.disabled = state;
37 if(state){
38 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-disabled');
39 }else{
40 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-node-disabled');
41 }
42 },
43
44 onSelectedChange : function(state){
45 if(state){
46 this.focus();
47 YAHOO.util.Dom.addClass(this.elNode, 'ytree-selected');
48 }else{
49 this.blur();
50 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-selected');
51 }
52 },
53
54 onMove : function(tree, node, oldParent, newParent, index, refNode){
55 this.childIndent = null;
56 if(this.rendered){
57 var targetNode = newParent.ui.getContainer();
58 if(!targetNode){//target not rendered
59 this.holder = document.createElement('div');
60 this.holder.appendChild(this.wrap);
61 return;
62 }
63 var insertBefore = refNode ? refNode.ui.getEl() : null;
64 if(insertBefore){
65 targetNode.insertBefore(this.wrap, insertBefore);
66 }else{
67 targetNode.appendChild(this.wrap);
68 }
69 this.node.renderIndent(true);
70 }
71 },
72
73 remove : function(){
74 if(this.rendered){
75 this.holder = document.createElement('div');
76 this.holder.appendChild(this.wrap);
77 }
78 },
79
80 fireEvent : function(){
81 this.node.fireEvent.apply(this.node, arguments);
82 },
83
84 initEvents : function(){
85 this.node.on('move', this.onMove, this, true);
86 //this.node.on('hiddenchange', this.onHiddenChange, this, true);
87
88 // these were optimized out but a custom UI could use them
89 //this.node.on('remove', this.onChildRemoved, this, true);
90 //this.node.on('selectedstatechange', this.onSelectedChange, this, true);
91 //this.node.on('disabledchange', this.onDisableChange, this, true);
92 //this.node.on('textchange', this.onTextChange, this, true);
93
94 var E = YAHOO.util.Event;
95 var a = this.anchor;
96
97 var el = YAHOO.ext.Element.fly(a);
98
99 if(YAHOO.ext.util.Browser.isOpera){ // opera render bug ignores the CSS
100 el.setStyle('text-decoration', 'none');
101 }
102
103 el.mon('click', this.onClick, this, true);
104 el.mon('dblclick', this.onDblClick, this, true);
105 el.mon('contextmenu', this.onContextMenu, this, true);
106
107 //el.on('focus', function(){
108 // this.node.getOwnerTree().getSelectionModel().select(this.node);
109 //}, this, true);
110
111 var icon = YAHOO.ext.Element.fly(this.iconNode);
112 icon.mon('click', this.onClick, this, true);
113 icon.mon('dblclick', this.onDblClick, this, true);
114 icon.mon('contextmenu', this.onContextMenu, this, true);
115 E.on(this.ecNode, 'click', this.ecClick, this, true);
116
117 if(this.node.disabled){
118 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-disabled');
119 }
120 if(this.node.hidden){
121 YAHOO.util.Dom.addClass(this.elNode, 'ytree-node-disabled');
122 }
123 var dd = this.node.ownerTree.enableDD || this.node.ownerTree.enableDrag || this.node.ownerTree.enableDrop;
124 if(dd && (!this.node.isRoot || this.node.ownerTree.rootVisible)){
125 YAHOO.ext.dd.Registry.register(this.elNode, {
126 node: this.node,
127 handles: [this.iconNode, this.textNode],
128 isHandle: false
129 });
130 }
131 },
132
133 hide : function(){
134 if(this.rendered){
135 this.wrap.style.display = 'none';
136 }
137 },
138
139 show : function(){
140 if(this.rendered){
141 this.wrap.style.display = '';
142 }
143 },
144
145 onContextMenu : function(e){
146 e.preventDefault();
147 this.focus();
148 this.fireEvent('contextmenu', this.node, e);
149 },
150
151 onClick : function(e){
152 if(this.dropping){
153 return;
154 }
155 if(this.fireEvent('beforeclick', this.node, e) !== false){
156 if(!this.disabled && this.node.attributes.href){
157 this.focus();
158 this.fireEvent('click', this.node, e);
159 return;
160 }
161 e.preventDefault();
162 if(this.disabled){
163 return;
164 }
165 this.focus();
166 this.fireEvent('click', this.node, e);
167 }else{
168 e.stopEvent();
169 }
170 },
171
172 onDblClick : function(e){
173 e.preventDefault();
174 if(this.disabled){
175 return;
176 }
177 if(!this.animating && this.node.hasChildNodes()){
178 this.node.toggle();
179 }
180 this.fireEvent('dblclick', this.node, e);
181 },
182
183 ecClick : function(e){
184 if(!this.animating && this.node.hasChildNodes()){
185 this.node.toggle();
186 }
187 },
188
189 startDrop : function(){
190 this.dropping = true;
191 },
192
193 // delayed drop so the click event doesn't get fired on a drop
194 endDrop : function(){
195 setTimeout(function(){
196 this.dropping = false;
197 }.createDelegate(this), 50);
198 },
199
200 expand : function(){
201 this.updateExpandIcon();
202 this.ctNode.style.display = '';
203 },
204
205 focus : function(){
206 try{
207 this.anchor.focus();
208 }catch(e){}
209 },
210
211 blur : function(){
212 try{
213 this.anchor.blur();
214 }catch(e){}
215 },
216
217 animExpand : function(callback){
218 if(this.animating && this.anim){
219 this.anim.stop();
220 }
221 this.animating = true;
222 this.updateExpandIcon();
223 var ct = this.ctNode;
224 var cs = ct.style;
225 cs.position = 'absolute';
226 cs.visibility = 'hidden';
227 cs.display = '';
228 var h = ct.clientHeight;
229 cs.overflow = 'hidden';
230 cs.height = '1px';
231 cs.position = '';
232 cs.visibility = '';
233 var anim = new YAHOO.util.Anim(ct, {
234 height: {to: h}
235 }, this.node.ownerTree.duration || .25, YAHOO.util.Easing.easeOut);
236 anim.onComplete.subscribe(function(){
237 cs.overflow = '';
238 cs.height = '';
239 this.animating = false;
240 this.anim = null;
241 if(typeof callback == 'function'){
242 callback();
243 }
244 }, this, true);
245 this.anim = anim;
246 anim.animate();
247 },
248
249 highlight : function(){
250 var tree = this.node.getOwnerTree();
251 var hlColor = tree.hlColor || 'C3DAF9';
252 var hlBaseColor = tree.hlBaseColor || 'FFFFFF';
253 var anim = new YAHOO.util.ColorAnim(this.wrap, {
254 backgroundColor: {from: hlColor, to: hlBaseColor}
255 }, .75, YAHOO.util.Easing.easeNone);
256 anim.onComplete.subscribe(function(){
257 YAHOO.util.Dom.setStyle(this.wrap, 'background-color', '');
258 }, this, true);
259 anim.animate();
260 },
261
262 collapse : function(){
263 this.updateExpandIcon();
264 this.ctNode.style.display = 'none';
265 },
266
267 animCollapse : function(callback){
268 if(this.animating && this.anim){
269 this.anim.stop();
270 }
271 this.animating = true;
272 this.updateExpandIcon();
273 var ct = this.ctNode;
274 var cs = ct.style;
275 cs.height = ct.offsetHeight +'px';
276 cs.overflow = 'hidden';
277 var anim = new YAHOO.util.Anim(ct, {
278 height: {to: 1}
279 }, this.node.ownerTree.duration || .25, YAHOO.util.Easing.easeOut);
280 anim.onComplete.subscribe(function(){
281 cs.display = 'none';
282 cs.overflow = '';
283 cs.height = '';
284 this.animating = false;
285 this.anim = null;
286 if(typeof callback == 'function'){
287 callback();
288 }
289 }, this, true);
290 this.anim = anim;
291 anim.animate();
292 },
293
294 getContainer : function(){
295 return this.ctNode;
296 },
297
298 getEl : function(){
299 return this.wrap;
300 },
301
302 appendDDGhost : function(ghostNode){
303 ghostNode.appendChild(this.elNode.cloneNode(true));
304 },
305
306 getDDRepairXY : function(){
307 return YAHOO.util.Dom.getXY(this.iconNode);
308 },
309
310 onRender : function(){
311 this.render();
312 },
313
314 render : function(bulkRender){
315 var n = this.node;
316 var targetNode = n.parentNode ?
317 n.parentNode.ui.getContainer() : n.ownerTree.container.dom;
318 if(!this.rendered){
319 this.rendered = true;
320 var a = n.attributes;
321
322 // add some indent caching, this helps performance when rendering a large tree
323 this.indentMarkup = '';
324 if(n.parentNode){
325 this.indentMarkup = n.parentNode.ui.getChildIndent();
326 }
327
328 var buf = ['<li class="ytree-node"><div class="ytree-node-el ', n.attributes.cls,'">',
329 '<span class="ytree-node-indent">',this.indentMarkup,'</span>',
330 '<img src="', this.emptyIcon, '" class="ytree-ec-icon">',
331 '<img src="', a.icon || this.emptyIcon, '" class="ytree-node-icon',(a.icon ? ' ytree-node-inline-icon' : ''),'" unselectable="on">',
332 '<a href="',a.href ? a.href : '#','" tabIndex="1" ',
333 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : '','><span unselectable="on">',n.text,'</span></a></div>',
334 '<ul class="ytree-node-ct" style="display:none;"></ul>',
335 '</li>'];
336
337 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
338 this.wrap = YAHOO.ext.DomHelper.insertHtml('beforeBegin',
339 n.nextSibling.ui.getEl(), buf.join(''));
340 }else{
341 this.wrap = YAHOO.ext.DomHelper.insertHtml('beforeEnd', targetNode, buf.join(''));
342 }
343 this.elNode = this.wrap.childNodes[0];
344 this.ctNode = this.wrap.childNodes[1];
345 var cs = this.elNode.childNodes;
346 this.indentNode = cs[0];
347 this.ecNode = cs[1];
348 this.iconNode = cs[2];
349 this.anchor = cs[3];
350 this.textNode = cs[3].firstChild;
351 if(a.qtip){
352 if(this.textNode.setAttributeNS){
353 this.textNode.setAttributeNS('y', 'qtip', a.qtip);
354 if(a.qtipTitle){
355 this.textNode.setAttributeNS('y', 'qtitle', a.qtipTitle);
356 }
357 }else{
358 this.textNode.setAttribute('y:qtip', a.qtip);
359 if(a.qtipTitle){
360 this.textNode.setAttribute('y:qtitle', a.qtipTitle);
361 }
362 }
363 }
364 this.initEvents();
365 //this.renderIndent(); cached above now instead call updateExpandIcon
366 this.updateExpandIcon();
367 }else{
368 if(bulkRender === true) {
369 targetNode.appendChild(this.wrap);
370 }
371 }
372 },
373
374 getAnchor : function(){
375 return this.anchor;
376 },
377
378 getTextEl : function(){
379 return this.textNode;
380 },
381
382 getIconEl : function(){
383 return this.iconNode;
384 },
385
386 updateExpandIcon : function(){
387 if(this.rendered){
388 var n = this.node;
389 var cls = n.isLast() ? "ytree-elbow-end" : "ytree-elbow";
390 var hasChild = n.hasChildNodes();
391 if(hasChild){
392 cls += n.expanded ? '-minus' : '-plus';
393 var c1 = n.expanded ? 'ytree-node-collapsed' : 'ytree-node-expanded';
394 var c2 = n.expanded ? 'ytree-node-expanded' : 'ytree-node-collapsed';
395 YAHOO.util.Dom.removeClass(this.elNode, 'ytree-node-leaf');
396 YAHOO.util.Dom.replaceClass(this.elNode, c1, c2);
397 }else{
398 YAHOO.util.Dom.replaceClass(this.elNode, 'ytree-node-expanded', 'ytree-node-leaf');
399 }
400 this.ecNode.className = 'ytree-ec-icon '+cls;
401 }
402 },
403
404 getChildIndent : function(){
405 if(!this.childIndent){
406 var buf = [];
407 var p = this.node;
408 while(p){
409 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
410 if(!p.isLast()) {
411 buf.unshift('<img src="'+this.emptyIcon+'" class="ytree-elbow-line">');
412 } else {
413 buf.unshift('<img src="'+this.emptyIcon+'" class="ytree-icon">');
414 }
415 }
416 p = p.parentNode;
417 }
418 this.childIndent = buf.join('');
419 }
420 return this.childIndent;
421 },
422
423 renderIndent : function(){
424 if(this.rendered){
425 var indent = '';
426 var p = this.node.parentNode;
427 if(p){
428 indent = p.ui.getChildIndent();
429 }
430 if(this.indentMarkup != indent){ // don't rerender if not required
431 this.indentNode.innerHTML = indent;
432 this.indentMarkup = indent;
433 }
434 this.updateExpandIcon();
435 }
436 }
437};
438
439YAHOO.ext.tree.RootTreeNodeUI = function(){
440 YAHOO.ext.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
441};
442YAHOO.extendX(YAHOO.ext.tree.RootTreeNodeUI, YAHOO.ext.tree.TreeNodeUI);
443YAHOO.ext.tree.RootTreeNodeUI.prototype.render = function(){
444 if(!this.rendered){
445 var targetNode = this.node.ownerTree.container.dom;
446 this.node.expanded = true;
447 targetNode.innerHTML = '<div class="ytree-root-node"></div>';
448 this.wrap = this.ctNode = targetNode.firstChild;
449 }
450};
451YAHOO.ext.tree.RootTreeNodeUI.prototype.collapse = function(){
452};
diff --git a/frontend/beta/js/YUI-extensions/tree/TreePanel.js b/frontend/beta/js/YUI-extensions/tree/TreePanel.js
new file mode 100644
index 0000000..202c0d0
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreePanel.js
@@ -0,0 +1,213 @@
1YAHOO.namespace('ext.tree');
2
3YAHOO.ext.tree.TreePanel = function(el, config){
4 YAHOO.ext.tree.TreePanel.superclass.constructor.call(this);
5 this.el = getEl(el);
6 this.id = this.el.id;
7 YAHOO.ext.util.Config.apply(this, config || {}, {
8 rootVisible : true,
9 lines : true,
10 enableDD : false,
11 hlDrop : true/*,
12 hlColor: null,
13 ddGroup : 'TreeDD'
14 hlBaseColor : 'FFFFFF'*/
15
16 });
17 YAHOO.ext.util.Config.apply(this.events, {
18 'beforeload' : true,
19 'load' : true,
20 'textchange' : true,
21 'beforeexpand' : true,
22 'beforecollapse' : true,
23 'expand' : true,
24 'collapse' : true,
25 'disabledchange' : true,
26 'beforeclick':true,
27 'click':true,
28 'dblclick':true,
29 'contentmenu':true,
30 'beforechildrenrendered':true,
31 /**
32 * @event startdrag
33 * Fires when a node starts being dragged
34 * @param {YAHOO.ext.tree.TreePanel} this
35 * @param {YAHOO.ext.tree.TreeNode} node
36 * @param {event} e The raw browser event
37 */
38 'startdrag' : true,
39 /**
40 * @event enddrag
41 * Fires when a drag operation is complete
42 * @param {YAHOO.ext.tree.TreePanel} this
43 * @param {YAHOO.ext.tree.TreeNode} node
44 * @param {event} e The raw browser event
45 */
46 'enddrag' : true,
47 /**
48 * @event dragdrop
49 * Fires when a dragged node is dropped on a valid DD target
50 * @param {YAHOO.ext.tree.TreePanel} this
51 * @param {YAHOO.ext.tree.TreeNode} node
52 * @param {DD} dd The dd it was dropped on
53 * @param {event} e The raw browser event
54 */
55 'dragdrop' : true,
56 /**
57 * @event beforenodedrop
58 * Fires when a DD object is dropped on a node in this tree for preprocessing. This event can cancel.
59 * @param {Object} dropEvent
60 */
61 'beforenodedrop' : true,
62 /**
63 * @event nodedrop
64 * Fires after a DD object is dropped on a node in this tree
65 * @param {Object} dropEvent
66 */
67 'nodedrop' : true,
68 /**
69 * @event nodedragover
70 * Fires when a tree node is being target
71 * @param {Object} dragOverEvent
72 */
73 'nodedragover' : true
74 });
75 if(this.singleExpand){
76 this.on('beforeexpand', this.restrictExpand, this, true);
77 }
78 // problem with safari and animation
79 // I am investigating
80 if(YAHOO.ext.util.Browser.isSafari){
81 this.animate = false;
82 }
83};
84YAHOO.extendX(YAHOO.ext.tree.TreePanel, YAHOO.ext.data.Tree, {
85 restrictExpand : function(node){
86 var p = node.parentNode;
87 if(p){
88 if(p.expandedChild && p.expandedChild.parentNode == p){
89 p.expandedChild.collapse();
90 }
91 p.expandedChild = node;
92 }
93 },
94
95 setRootNode : function(node){
96 YAHOO.ext.tree.TreePanel.superclass.setRootNode.call(this, node);
97 if(!this.rootVisible){
98 node.ui = new YAHOO.ext.tree.RootTreeNodeUI(node);
99 }
100 return node;
101 },
102
103 getEl : function(){
104 return this.el;
105 },
106
107 getLoader : function(){
108 return this.loader;
109 },
110
111 expandAll : function(){
112 this.root.expand(true);
113 },
114
115 collapseAll : function(){
116 this.root.collapse(true);
117 },
118
119 getSelectionModel : function(){
120 if(!this.selModel){
121 this.selModel = new YAHOO.ext.tree.DefaultSelectionModel();
122 }
123 return this.selModel;
124 },
125
126 expandPath : function(path, attr, callback){
127 attr = attr || 'id';
128 var keys = path.split(this.pathSeparator);
129 var curNode = this.root;
130 if(curNode.attributes[attr] != keys[1]){ // invalid root
131 if(callback){
132 callback(false, null);
133 }
134 return;
135 }
136 var index = 1;
137 var f = function(){
138 if(++index == keys.length){
139 if(callback){
140 callback(true, curNode);
141 }
142 return;
143 }
144 var c = curNode.findChild(attr, keys[index]);
145 if(!c){
146 if(callback){
147 callback(false, curNode);
148 }
149 return;
150 }
151 curNode = c;
152 c.expand(false, false, f);
153 }
154 curNode.expand(false, false, f);
155 },
156
157 selectPath : function(path, attr, callback){
158 attr = attr || 'id';
159 var keys = path.split(this.pathSeparator);
160 var v = keys.pop();
161 if(keys.length > 0){
162 var f = function(success, node){
163 if(success && node){
164 var n = node.findChild(attr, v);
165 if(n){
166 n.select();
167 if(callback){
168 callback(true, n);
169 }
170 }
171 }else{
172 if(callback){
173 callback(false, n);
174 }
175 }
176 };
177 this.expandPath(keys.join(this.pathSeparator), attr, f);
178 }else{
179 this.root.select();
180 if(callback){
181 callback(true, this.root);
182 }
183 }
184 },
185
186 render : function(){
187 this.container = this.el.createChild({tag:'ul',
188 cls:'ytree-root-ct ' +
189 (this.lines ? 'ytree-lines' : 'ytree-no-lines')});
190
191 if(this.containerScroll){
192 YAHOO.ext.dd.ScrollManager.register(this.el);
193 }
194
195 if((this.enableDD || this.enableDrop) && !this.dropZone){
196 this.dropZone = new YAHOO.ext.tree.TreeDropZone(this, this.dropConfig || {
197 ddGroup: this.ddGroup || 'TreeDD'
198 });
199 }
200 if((this.enableDD || this.enableDrag) && !this.dragZone){
201 this.dragZone = new YAHOO.ext.tree.TreeDragZone(this, this.dragConfig || {
202 ddGroup: this.ddGroup || 'TreeDD',
203 scroll: this.ddScroll
204 });
205 }
206 this.getSelectionModel().init(this);
207 this.root.render();
208 if(!this.rootVisible){
209 this.root.renderChildren();
210 }
211 return this;
212 }
213});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js b/frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js
new file mode 100644
index 0000000..4fed88e
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeSelectionModel.js
@@ -0,0 +1,195 @@
1YAHOO.ext.tree.DefaultSelectionModel = function(){
2 this.selNode = null;
3
4 this.events = {
5 'selectionchange' : true
6 };
7};
8
9YAHOO.extendX(YAHOO.ext.tree.DefaultSelectionModel, YAHOO.ext.util.Observable, {
10 init : function(tree){
11 this.tree = tree;
12 tree.el.mon('keydown', this.onKeyDown, this, true);
13 tree.on('click', this.onNodeClick, this, true);
14 },
15
16 onNodeClick : function(node, e){
17 this.select(node);
18 },
19
20 select : function(node){
21 if(this.selNode && this.selNode != node){
22 this.selNode.ui.onSelectedChange(false);
23 }
24 this.selNode = node;
25 node.ui.onSelectedChange(true);
26 this.fireEvent('selectionchange', this, node);
27 return node;
28 },
29
30 unselect : function(node){
31 if(this.selNode == node){
32 this.clearSelections();
33 }
34 },
35
36 clearSelections : function(){
37 var n = this.selNode;
38 if(n){
39 n.ui.onSelectedChange(false);
40 this.selNode = null;
41 this.fireEvent('selectionchange', this, null);
42 }
43 return n;
44 },
45
46 getSelectedNode : function(){
47 return this.selNode;
48 },
49
50 isSelected : function(node){
51 return this.selNode == node;
52 },
53
54 onKeyDown : function(e){
55 var s = this.selNode || this.lastSelNode;
56 // undesirable, but required
57 var sm = this;
58 if(!s){
59 return;
60 }
61 var k = e.getKey();
62 //alert(k)
63 switch(k){
64 case e.DOWN:
65 e.preventDefault();
66 if(s.firstChild && s.isExpanded()){
67 this.select(s.firstChild, e);
68 }else if(s.nextSibling){
69 this.select(s.nextSibling, e);
70 }else if(s.parentNode){
71 s.parentNode.bubble(function(){
72 if(this.nextSibling){
73 sm.select(this.nextSibling, e);
74 return false;
75 }
76 });
77 }
78 break;
79 case e.UP:
80 e.preventDefault();
81 var ps = s.previousSibling;
82 if(ps){
83 if(!ps.isExpanded()){
84 this.select(ps, e);
85 }else{
86 var lc = ps.lastChild;
87 while(lc && lc.isExpanded()){
88 lc = lc.lastChild;
89 }
90 this.select(lc, e);
91 }
92 }else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
93 this.select(s.parentNode, e);
94 }
95 break;
96 case e.RIGHT:
97 e.preventDefault();
98 if(s.hasChildNodes()){
99 if(!s.isExpanded()){
100 s.expand();
101 }else if(s.firstChild){
102 this.select(s.firstChild, e);
103 }
104 }
105 break;
106 case e.LEFT:
107 e.preventDefault();
108 if(s.hasChildNodes() && s.isExpanded()){
109 s.collapse();
110 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
111 this.select(s.parentNode, e);
112 }
113 break;
114 };
115 }
116});
117
118YAHOO.ext.tree.MultiSelectionModel = function(){
119 this.selNodes = [];
120 this.selMap = {};
121 this.events = {
122 'selectionchange' : true
123 };
124};
125
126YAHOO.extendX(YAHOO.ext.tree.MultiSelectionModel, YAHOO.ext.util.Observable, {
127 init : function(tree){
128 this.tree = tree;
129 tree.el.mon('keydown', this.onKeyDown, this, true);
130 tree.on('click', this.onNodeClick, this, true);
131 },
132
133 onNodeClick : function(node, e){
134 this.select(node, e, e.ctrlKey);
135 },
136
137 select : function(node, e, keepExisting){
138 if(keepExisting !== true){
139 this.clearSelections(true);
140 }
141 this.selNodes.push(node);
142 this.selMap[node.id] = node;
143 this.lastSelNode = node;
144 node.ui.onSelectedChange(true);
145 this.fireEvent('selectionchange', this, this.selNodes);
146 return node;
147 },
148
149 unselect : function(node){
150 if(this.selMap[node.id]){
151 node.ui.onSelectedChange(false);
152 var sn = this.selNodes;
153 var index = -1;
154 if(sn.indexOf){
155 index = sn.indexOf(node);
156 }else{
157 for(var i = 0, len = sn.length; i < len; i++){
158 if(sn[i] == node){
159 index = i;
160 break;
161 }
162 }
163 }
164 if(index != -1){
165 this.selNodes.splice(index, 1);
166 }
167 delete this.selMap[node.id];
168 this.fireEvent('selectionchange', this, this.selNodes);
169 }
170 },
171
172 clearSelections : function(suppressEvent){
173 var sn = this.selNodes;
174 if(sn.length > 0){
175 for(var i = 0, len = sn.length; i < len; i++){
176 sn[i].ui.onSelectedChange(false);
177 }
178 this.selNodes = [];
179 this.selMap = {};
180 if(suppressEvent !== true){
181 this.fireEvent('selectionchange', this, this.selNodes);
182 }
183 }
184 },
185
186 isSelected : function(node){
187 return this.selMap[node.id] ? true : false;
188 },
189
190 getSelectedNodes : function(){
191 return this.selNodes;
192 },
193
194 onKeyDown : YAHOO.ext.tree.DefaultSelectionModel.prototype.onKeyDown
195});
diff --git a/frontend/beta/js/YUI-extensions/tree/TreeSorter.js b/frontend/beta/js/YUI-extensions/tree/TreeSorter.js
new file mode 100644
index 0000000..9960703
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/tree/TreeSorter.js
@@ -0,0 +1,49 @@
1YAHOO.ext.tree.TreeSorter = function(tree, config){
2 YAHOO.ext.util.Config.apply(this, config);
3 tree.on('beforechildrenrendered', this.doSort, this, true);
4 tree.on('append', this.updateSort, this, true);
5 tree.on('insert', this.updateSort, this, true);
6
7 var dsc = this.dir && this.dir.toLowerCase() == 'desc';
8 var p = this.property || 'text';
9 var sortType = this.sortType;
10 var fs = this.folderSort;
11 var cs = this.caseSensitive === true;
12
13 this.sortFn = function(n1, n2){
14 if(fs){
15 if(n1.leaf && !n2.leaf){
16 return 1;
17 }
18 if(!n1.leaf && n2.leaf){
19 return -1;
20 }
21 }
22 var v1 = sortType ? sortType(n1) : (cs ? n1[p] : n1[p].toUpperCase());
23 var v2 = sortType ? sortType(n2) : (cs ? n2[p] : n2[p].toUpperCase());
24 if(v1 < v2){
25 return dsc ? +1 : -1;
26 }else if(v1 > v2){
27 return dsc ? -1 : +1;
28 }else{
29 return 0;
30 }
31 };
32};
33
34YAHOO.ext.tree.TreeSorter.prototype = {
35 doSort : function(node){
36 node.sort(this.sortFn);
37 },
38
39 compareNodes : function(n1, n2){
40
41 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
42 },
43
44 updateSort : function(tree, node){
45 if(node.childrenRendered){
46 this.doSort.defer(1, this, [node]);
47 }
48 }
49};