3 <title>The source code</title>
\r
4 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
\r
5 <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
\r
7 <body onload="prettyPrint();">
\r
8 <pre class="prettyprint lang-js">// custom menu item to contain Ext trees
\r
9 Ext.menu.TreeItem = Ext.extend(Ext.menu.Adapter, {
\r
10 constructor : function(config){
\r
11 Ext.menu.TreeItem.superclass.constructor.call(this, config.tree, config);
\r
12 this.tree = this.component;
\r
13 this.addEvents('selectionchange');
\r
15 this.tree.on("render", function(tree){
\r
16 tree.body.swallowEvent(['click','keydown', 'keypress', 'keyup']);
\r
19 this.tree.getSelectionModel().on("selectionchange", this.onSelect, this);
\r
22 onSelect : function(tree, sel){
\r
23 this.fireEvent("select", this, sel, tree);
\r
28 // custom menu containing a single tree
\r
29 Ext.menu.TreeMenu = Ext.extend(Ext.menu.Menu, {
\r
35 constructor : function(config){
\r
36 Ext.menu.TreeMenu.superclass.constructor.call(this, config);
\r
37 this.treeItem = new Ext.menu.TreeItem(config);
\r
38 this.add(this.treeItem);
\r
40 this.tree = this.treeItem.tree;
\r
41 this.tree.on('click', this.onNodeClick, this);
\r
42 this.relayEvents(this.treeItem, ["selectionchange"]);
\r
46 beforeDestroy : function() {
\r
47 this.tree.destroy();
\r
50 onNodeClick : function(node, e){
\r
51 if(!node.attributes.isFolder){
\r
52 this.treeItem.handleClick(e);
\r
58 // custom form field for displaying a tree, similar to select or combo
\r
59 Ext.ux.TreeSelector = Ext.extend(Ext.form.TriggerField, {
\r
60 initComponent : function(){
\r
61 Ext.ux.TreeSelector.superclass.initComponent.call(this);
\r
62 this.addEvents('selectionchange');
\r
64 this.tree.getSelectionModel().on('selectionchange', this.onSelection, this);
\r
66 'expandnode': this.sync,
\r
67 'collapsenode' : this.sync,
\r
68 'append' : this.sync,
\r
69 'remove' : this.sync,
\r
70 'insert' : this.sync,
\r
73 this.on('focus', this.onTriggerClick, this);
\r
77 if(this.menu && this.menu.isVisible()){
\r
78 if(this.tree.body.getHeight() > this.maxHeight){
\r
79 this.tree.body.setHeight(this.maxHeight);
\r
80 this.restricted = true;
\r
81 }else if(this.restricted && this.tree.body.dom.firstChild.offsetHeight < this.maxHeight){
\r
82 this.tree.body.setHeight('');
\r
83 this.restricted = false;
\r
85 this.menu.el.sync();
\r
89 onSelection : function(tree, node){
\r
91 this.setRawValue('');
\r
93 this.setRawValue(node.text);
\r
97 initEvents : function(){
\r
98 Ext.ux.TreeSelector.superclass.initEvents.call(this);
\r
99 this.el.on('mousedown', this.onTriggerClick, this);
\r
100 this.el.on("keydown", this.onKeyDown, this);
\r
103 onKeyDown : function(e){
\r
104 if(e.getKey() == e.DOWN){
\r
105 this.onTriggerClick();
\r
109 validateBlur : function(){
\r
110 return !this.menu || !this.menu.isVisible();
\r
113 getValue : function(){
\r
114 var sm = this.tree.getSelectionModel();
\r
115 var s = sm.getSelectedNode();
\r
116 return s ? s.id : '';
\r
119 setValue : function(id){
\r
120 var n = this.tree.getNodeById(id);
\r
124 this.tree.getSelectionModel().clearSelections();
\r
129 onDestroy : function(){
\r
131 this.menu.destroy();
\r
134 this.wrap.remove();
\r
136 Ext.ux.TreeSelector.superclass.onDestroy.call(this);
\r
141 show : function(){ // retain focus styling
\r
145 this.focus.defer(10, this);
\r
146 var ml = this.menuListeners;
\r
147 this.menu.un("show", ml.show, this);
\r
148 this.menu.un("hide", ml.hide, this);
\r
152 onTriggerClick : function(){
\r
156 this.menu.on(Ext.apply({}, this.menuListeners, {
\r
160 this.menu.show(this.el, "tl-bl?");
\r
162 var sm = this.tree.getSelectionModel();
\r
163 var selected = sm.getSelectedNode();
\r
165 selected.ensureVisible();
\r
166 sm.activate.defer(250, sm, [selected]);
\r
170 beforeBlur : function(){
\r
174 onRender : function(){
\r
175 Ext.ux.TreeSelector.superclass.onRender.apply(this, arguments);
\r
176 this.menu = new Ext.menu.TreeMenu(Ext.apply(this.menuConfig || {}, {tree: this.tree}));
\r
177 this.menu.render();
\r
179 this.tree.body.addClass('x-tree-selector');
\r
186 * Custom tree keyboard navigation that supports node navigation without selection
\r
188 Ext.tree.ActivationModel = Ext.extend(Ext.tree.DefaultSelectionModel, {
\r
189 select : function(node){
\r
190 return this.activate(Ext.tree.ActivationModel.superclass.select.call(this, node));
\r
193 activate : function(node){
\r
197 if(this.activated != node) {
\r
198 if(this.activated){
\r
199 this.activated.ui.removeClass('x-tree-activated');
\r
201 this.activated = node;
\r
202 node.ui.addClass('x-tree-activated');
\r
208 activatePrevious : function(){
\r
209 var s = this.activated;
\r
213 var ps = s.previousSibling;
\r
215 if(!ps.isExpanded() || ps.childNodes.length < 1){
\r
216 return this.activate(ps);
\r
218 var lc = ps.lastChild;
\r
219 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
\r
222 return this.activate(lc);
\r
224 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
\r
225 return this.activate(s.parentNode);
\r
230 activateNext : function(){
\r
231 var s = this.activated;
\r
235 if(s.firstChild && s.isExpanded()){
\r
236 return this.activate(s.firstChild);
\r
237 }else if(s.nextSibling){
\r
238 return this.activate(s.nextSibling);
\r
239 }else if(s.parentNode){
\r
241 s.parentNode.bubble(function(){
\r
242 if(this.nextSibling){
\r
243 newS = this.getOwnerTree().selModel.activate(this.nextSibling);
\r
252 onKeyDown : function(e){
\r
253 var s = this.activated;
\r
254 // undesirable, but required
\r
259 var k = e.getKey();
\r
263 this.activateNext();
\r
267 this.activatePrevious();
\r
270 e.preventDefault();
\r
271 if(s.hasChildNodes()){
\r
272 if(!s.isExpanded()){
\r
274 }else if(s.firstChild){
\r
275 this.activate(s.firstChild, e);
\r
280 e.preventDefault();
\r
281 if(s.hasChildNodes() && s.isExpanded()){
\r
283 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
\r
284 this.activate(s.parentNode, e);
\r