YUI Library Examples: Menu Family: Adding A Context Menu To A TreeView

Menu Family: Adding A Context Menu To A TreeView

This example demonstates how to use the ContextMenu widget to add a context menu to a YUI TreeView control. The context menu allows the user to add, edit and remove items from a TreeView instance.

Please Note: Opera users will need to do the following to use this example:

  • Opera for Windows: Hold down the control key and click with the left mouse button.
  • Opera for OS X: Hold down the command key (⌘) and click with the left mouse button.

When adding context menus to large data structures like a <table> or large list (<ol> or <ul>), it is recommended to bind a single YAHOO.widget.ContextMenu instance to the structure's root element, than to a set of its child nodes (<tr>s or <li>s). Doing so significantly improves the performance of a web page or application by reducing the number of "contextmenu" event handlers as well as the number of YAHOO.widget.ContextMenu instances in memory.

Begin by creating a TreeView instance. Next, create an object that maps HTML ids to their corresponding TextNode instances. As each TextNode instance is added to the TreeView, store a reference to it in the map.

1/*
2     Initialize the TreeView instance when the "mytreeview" <div>
3     is ready to be scripted.
4*/ 
5 
6YAHOO.util.Event.onAvailable("mytreeview"function () { 
7 
8    /*
9         Map of YAHOO.widget.TextNode instances in the 
10         TreeView instance.
11    */ 
12 
13    var oTextNodeMap = {}; 
14 
15 
16    // Creates a TextNode instance and appends it to the TreeView  
17 
18    function buildRandomTextBranch(p_oNode) { 
19 
20        var oTextNode, 
21            i; 
22 
23        if (p_oNode.depth < 6) { 
24 
25            for (i = 0; i < Math.floor(Math.random() * 4); i++) { 
26 
27                oTextNode = new YAHOO.widget.TextNode(p_oNode.label + "-" + i, p_oNode, false); 
28 
29                oTextNodeMap[oTextNode.labelElId] = oTextNode; 
30                 
31                buildRandomTextBranch(oTextNode); 
32 
33            } 
34 
35        } 
36 
37    } 
38 
39 
40    // Create a TreeView instance 
41 
42    var oTreeView = new YAHOO.widget.TreeView("mytreeview"); 
43 
44    var n, oTextNode; 
45 
46    for (n = 0; n < Math.floor((Math.random()*4) + 3); n++) { 
47 
48        oTextNode = new YAHOO.widget.TextNode("label-" + n, oTreeView.getRoot(), false); 
49         
50        /*
51             Add the TextNode instance to the map, using its
52             HTML id as the key.
53        */ 
54         
55        oTextNodeMap[oTextNode.labelElId] = oTextNode; 
56         
57        buildRandomTextBranch(oTextNode); 
58 
59    } 
60 
61    oTreeView.draw(); 
62 
63}); 
view plain | print | ?

Once the TreeView is created, instantiate a ContextMenu specifying the TreeView instance's root element as its trigger. Lastly, add a "triggerContextMenu" event handler for the ContextMenu instance that uses the "contextEventTarget" property to retrieve the TextNode instance that triggered its display. A reference to the TextNode is stored in a variable (oCurrentTextNode), so that it can be manipulated by the addNode, editNodeLabel, and deleteNode functions.

1/*
2     The YAHOO.widget.TextNode instance whose "contextmenu" 
3     DOM event triggered the display of the 
4     ContextMenu instance.
5*/ 
6 
7var oCurrentTextNode = null
8 
9 
10/*
11     Adds a new TextNode as a child of the TextNode instance 
12     that was the target of the "contextmenu" event that 
13     triggered the display of the ContextMenu instance.
14*/ 
15 
16function addNode() { 
17 
18    var sLabel = window.prompt("Enter a label for the new node: """), 
19        oChildNode; 
20 
21    if (sLabel && sLabel.length > 0) { 
22         
23        oChildNode = new YAHOO.widget.TextNode(sLabel, oCurrentTextNode, false); 
24 
25        oCurrentTextNode.refresh(); 
26        oCurrentTextNode.expand(); 
27 
28        oTextNodeMap[oChildNode.labelElId] = oChildNode; 
29 
30    } 
31 
32
33 
34 
35/*
36     Edits the label of the TextNode that was the target of the
37     "contextmenu" event that triggered the display of the 
38     ContextMenu instance.
39*/ 
40 
41function editNodeLabel() { 
42 
43    var sLabel = window.prompt("Enter a new label for this node: ", oCurrentTextNode.getLabelEl().innerHTML); 
44 
45    if (sLabel && sLabel.length > 0) { 
46         
47        oCurrentTextNode.getLabelEl().innerHTML = sLabel; 
48 
49    } 
50 
51
52 
53 
54/*
55    Deletes the TextNode that was the target of the "contextmenu"
56    event that triggered the display of the ContextMenu instance.
57*/ 
58 
59function deleteNode() { 
60 
61    delete oTextNodeMap[oCurrentTextNode.labelElId]; 
62 
63    oTreeView.removeNode(oCurrentTextNode); 
64    oTreeView.draw(); 
65 
66
67 
68 
69/*
70    "contextmenu" event handler for the element(s) that 
71    triggered the display of the ContextMenu instance - used
72    to set a reference to the TextNode instance that triggered
73    the display of the ContextMenu instance.
74*/ 
75 
76function onTriggerContextMenu(p_oEvent) { 
77 
78 
79    /*
80         Returns a TextNode instance that corresponds to the DOM
81         element whose "contextmenu" event triggered the display
82         of the ContextMenu instance.
83    */ 
84 
85    function getTextNodeFromEventTarget(p_oTarget) { 
86 
87        if (p_oTarget.tagName.toUpperCase() == "A" &&  
88                p_oTarget.className == "ygtvlabel") { 
89 
90            return oTextNodeMap[p_oTarget.id]; 
91 
92        } 
93        else { 
94 
95            if (p_oTarget.parentNode &&  
96                    p_oTarget.parentNode.nodeType == 1) { 
97 
98                return getTextNodeFromEventTarget(p_oTarget.parentNode); 
99             
100            } 
101         
102        } 
103     
104    } 
105 
106 
107    /*
108         Get the TextNode instance that that triggered the 
109         display of the ContextMenu instance.
110    */ 
111 
112    var oTextNode = getTextNodeFromEventTarget(this.contextEventTarget); 
113 
114 
115    if (oTextNode) { 
116 
117        oCurrentTextNode = oTextNode; 
118 
119    } 
120    else { 
121     
122        // Cancel the display of the ContextMenu instance. 
123     
124        this.cancel(); 
125         
126    } 
127 
128
129 
130 
131/*
132     Instantiate a ContextMenu:  The first argument passed to 
133     the constructor is the id of the element to be created; the 
134     second is an object literal of configuration properties.
135*/ 
136 
137var oContextMenu = new YAHOO.widget.ContextMenu("mytreecontextmenu", { 
138                                                trigger: "mytreeview"
139                                                lazyload: true,  
140                                                itemdata: [ 
141                                                    { text: "Add Child Node", onclick: { fn: addNode } }, 
142                                                    { text: "Edit Node Label", onclick: { fn: editNodeLabel } }, 
143                                                    { text: "Delete Node", onclick: { fn: deleteNode } } 
144                                                ] }); 
145 
146 
147/*
148     Subscribe to the "contextmenu" event for the element(s)
149     specified as the "trigger" for the ContextMenu instance.
150*/ 
151 
152oContextMenu.subscribe("triggerContextMenu", onTriggerContextMenu); 
view plain | print | ?

Menu Family Examples:

More Menu Family Resources:

Copyright © 2008 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings