The TaskNode example implements a task list using treeview. It does so by extending the TextNode class to have additional, specific functionality. In this example, each TaskNode has three potential states: Checked, partially-checked (not all subtasks complete), and unchecked. Checking off a task automatically checks off all subtasks.
This example explores the extension of TreeView via a subclass of the TextNode class. The full source of the TaskNode subclass follows:
1 | /** |
2 | * The check box marks a task complete. It is a simulated form field |
3 | * with three states ... |
4 | * 0=unchecked, 1=some children checked, 2=all children checked |
5 | * When a task is clicked, the state of the nodes and parent and children |
6 | * are updated, and this behavior cascades. |
7 | * |
8 | * @extends YAHOO.widget.TextNode |
9 | * @constructor |
10 | * @param oData {object} A string or object containing the data that will |
11 | * be used to render this node. |
12 | * @param oParent {Node} This node's parent node |
13 | * @param expanded {boolean} The initial expanded/collapsed state |
14 | * @param checked {boolean} The initial checked/unchecked state |
15 | */ |
16 | YAHOO.widget.TaskNode = function(oData, oParent, expanded, checked) { |
17 | |
18 | if (YAHOO.widget.LogWriter) { |
19 | this.logger = new YAHOO.widget.LogWriter(this.toString()); |
20 | } else { |
21 | this.logger = YAHOO; |
22 | } |
23 | |
24 | if (oData) { |
25 | this.init(oData, oParent, expanded); |
26 | this.setUpLabel(oData); |
27 | this.setUpCheck(checked); |
28 | } |
29 | |
30 | }; |
31 | |
32 | YAHOO.extend(YAHOO.widget.TaskNode, YAHOO.widget.TextNode, { |
33 | |
34 | /** |
35 | * True if checkstate is 1 (some children checked) or 2 (all children checked), |
36 | * false if 0. |
37 | * @type boolean |
38 | */ |
39 | checked: false, |
40 | |
41 | /** |
42 | * checkState |
43 | * 0=unchecked, 1=some children checked, 2=all children checked |
44 | * @type int |
45 | */ |
46 | checkState: 0, |
47 | |
48 | taskNodeParentChange: function() { |
49 | //this.updateParent(); |
50 | }, |
51 | |
52 | setUpCheck: function(checked) { |
53 | // if this node is checked by default, run the check code to update |
54 | // the parent's display state |
55 | if (checked && checked === true) { |
56 | this.check(); |
57 | // otherwise the parent needs to be updated only if its checkstate |
58 | // needs to change from fully selected to partially selected |
59 | } else if (this.parent && 2 == this.parent.checkState) { |
60 | this.updateParent(); |
61 | } |
62 | |
63 | // set up the custom event on the tree for checkClick |
64 | /** |
65 | * Custom event that is fired when the check box is clicked. The |
66 | * custom event is defined on the tree instance, so there is a single |
67 | * event that handles all nodes in the tree. The node clicked is |
68 | * provided as an argument. Note, your custom node implentation can |
69 | * implement its own node specific events this way. |
70 | * |
71 | * @event checkClick |
72 | * @for YAHOO.widget.TreeView |
73 | * @param {YAHOO.widget.Node} node the node clicked |
74 | */ |
75 | if (this.tree && !this.tree.hasEvent("checkClick")) { |
76 | this.tree.createEvent("checkClick", this.tree); |
77 | } |
78 | |
79 | this.subscribe("parentChange", this.taskNodeParentChange); |
80 | |
81 | }, |
82 | |
83 | /** |
84 | * The id of the check element |
85 | * @for YAHOO.widget.TaskNode |
86 | * @type string |
87 | */ |
88 | getCheckElId: function() { |
89 | return "ygtvcheck" + this.index; |
90 | }, |
91 | |
92 | /** |
93 | * Returns the check box element |
94 | * @return the check html element (img) |
95 | */ |
96 | getCheckEl: function() { |
97 | return document.getElementById(this.getCheckElId()); |
98 | }, |
99 | |
100 | /** |
101 | * The style of the check element, derived from its current state |
102 | * @return {string} the css style for the current check state |
103 | */ |
104 | getCheckStyle: function() { |
105 | return "ygtvcheck" + this.checkState; |
106 | }, |
107 | |
108 | /** |
109 | * Returns the link that will invoke this node's check toggle |
110 | * @return {string} returns the link required to adjust the checkbox state |
111 | */ |
112 | getCheckLink: function() { |
113 | return "YAHOO.widget.TreeView.getNode(\'" + this.tree.id + "\'," + |
114 | this.index + ").checkClick()"; |
115 | }, |
116 | |
117 | /** |
118 | * Invoked when the user clicks the check box |
119 | */ |
120 | checkClick: function() { |
121 | this.logger.log("previous checkstate: " + this.checkState); |
122 | if (this.checkState === 0) { |
123 | this.check(); |
124 | } else { |
125 | this.uncheck(); |
126 | } |
127 | |
128 | this.onCheckClick(this); |
129 | this.tree.fireEvent("checkClick", this); |
130 | }, |
131 | |
132 | /** |
133 | * Override to get the check click event |
134 | */ |
135 | onCheckClick: function() { |
136 | this.logger.log("onCheckClick: " + this); |
137 | }, |
138 | |
139 | /** |
140 | * Refresh the state of this node's parent, and cascade up. |
141 | */ |
142 | updateParent: function() { |
143 | var p = this.parent; |
144 | |
145 | if (!p || !p.updateParent) { |
146 | this.logger.log("Abort udpate parent: " + this.index); |
147 | return; |
148 | } |
149 | |
150 | var somethingChecked = false; |
151 | var somethingNotChecked = false; |
152 | |
153 | for (var i=0;i< p.children.length;++i) { |
154 | if (p.children[i].checked) { |
155 | somethingChecked = true; |
156 | // checkState will be 1 if the child node has unchecked children |
157 | if (p.children[i].checkState == 1) { |
158 | somethingNotChecked = true; |
159 | } |
160 | } else { |
161 | somethingNotChecked = true; |
162 | } |
163 | } |
164 | |
165 | if (somethingChecked) { |
166 | p.setCheckState( (somethingNotChecked) ? 1 : 2 ); |
167 | } else { |
168 | p.setCheckState(0); |
169 | } |
170 | |
171 | p.updateCheckHtml(); |
172 | p.updateParent(); |
173 | }, |
174 | |
175 | /** |
176 | * If the node has been rendered, update the html to reflect the current |
177 | * state of the node. |
178 | */ |
179 | updateCheckHtml: function() { |
180 | if (this.parent && this.parent.childrenRendered) { |
181 | this.getCheckEl().className = this.getCheckStyle(); |
182 | } |
183 | }, |
184 | |
185 | /** |
186 | * Updates the state. The checked property is true if the state is 1 or 2 |
187 | * |
188 | * @param the new check state |
189 | */ |
190 | setCheckState: function(state) { |
191 | this.checkState = state; |
192 | this.checked = (state > 0); |
193 | }, |
194 | |
195 | /** |
196 | * Check this node |
197 | */ |
198 | check: function() { |
199 | this.logger.log("check"); |
200 | this.setCheckState(2); |
201 | for (var i=0; i<this.children.length; ++i) { |
202 | this.children[i].check(); |
203 | } |
204 | this.updateCheckHtml(); |
205 | this.updateParent(); |
206 | }, |
207 | |
208 | /** |
209 | * Uncheck this node |
210 | */ |
211 | uncheck: function() { |
212 | this.setCheckState(0); |
213 | for (var i=0; i<this.children.length; ++i) { |
214 | this.children[i].uncheck(); |
215 | } |
216 | this.updateCheckHtml(); |
217 | this.updateParent(); |
218 | }, |
219 | |
220 | // Overrides YAHOO.widget.TextNode |
221 | getNodeHtml: function() { |
222 | this.logger.log("Generating html"); |
223 | var sb = []; |
224 | |
225 | var getNode = 'YAHOO.widget.TreeView.getNode(\'' + |
226 | this.tree.id + '\',' + this.index + ')'; |
227 | |
228 | |
229 | sb[sb.length] = '<table border="0" cellpadding="0" cellspacing="0">'; |
230 | sb[sb.length] = '<tr>'; |
231 | |
232 | for (var i=0;i<this.depth;++i) { |
233 | //sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"> </td>'; |
234 | sb[sb.length] = '<td class="' + this.getDepthStyle(i) + '"><div class="ygtvspacer"></div></td>'; |
235 | } |
236 | |
237 | sb[sb.length] = '<td'; |
238 | sb[sb.length] = ' id="' + this.getToggleElId() + '"'; |
239 | sb[sb.length] = ' class="' + this.getStyle() + '"'; |
240 | if (this.hasChildren(true)) { |
241 | sb[sb.length] = ' onmouseover="this.className='; |
242 | sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; |
243 | sb[sb.length] = this.tree.id + '\',' + this.index + ').getHoverStyle()"'; |
244 | sb[sb.length] = ' onmouseout="this.className='; |
245 | sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; |
246 | sb[sb.length] = this.tree.id + '\',' + this.index + ').getStyle()"'; |
247 | } |
248 | sb[sb.length] = ' onclick="javascript:' + this.getToggleLink() + '"> '; |
249 | //sb[sb.length] = '</td>'; |
250 | sb[sb.length] = '<div class="ygtvspacer"></div></td>'; |
251 | |
252 | // check box |
253 | sb[sb.length] = '<td'; |
254 | sb[sb.length] = ' id="' + this.getCheckElId() + '"'; |
255 | sb[sb.length] = ' class="' + this.getCheckStyle() + '"'; |
256 | sb[sb.length] = ' onclick="javascript:' + this.getCheckLink() + '">'; |
257 | //sb[sb.length] = ' </td>'; |
258 | sb[sb.length] = '<div class="ygtvspacer"></div></td>'; |
259 | |
260 | |
261 | sb[sb.length] = '<td>'; |
262 | sb[sb.length] = '<a'; |
263 | sb[sb.length] = ' id="' + this.labelElId + '"'; |
264 | sb[sb.length] = ' class="' + this.labelStyle + '"'; |
265 | sb[sb.length] = ' href="' + this.href + '"'; |
266 | sb[sb.length] = ' target="' + this.target + '"'; |
267 | sb[sb.length] = ' onclick="return ' + getNode + '.onLabelClick(' + getNode +')"'; |
268 | if (this.hasChildren(true)) { |
269 | sb[sb.length] = ' onmouseover="document.getElementById(\''; |
270 | sb[sb.length] = this.getToggleElId() + '\').className='; |
271 | sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; |
272 | sb[sb.length] = this.tree.id + '\',' + this.index + ').getHoverStyle()"'; |
273 | sb[sb.length] = ' onmouseout="document.getElementById(\''; |
274 | sb[sb.length] = this.getToggleElId() + '\').className='; |
275 | sb[sb.length] = 'YAHOO.widget.TreeView.getNode(\''; |
276 | sb[sb.length] = this.tree.id + '\',' + this.index + ').getStyle()"'; |
277 | } |
278 | sb[sb.length] = (this.nowrap) ? ' nowrap="nowrap" ' : ''; |
279 | sb[sb.length] = ' >'; |
280 | sb[sb.length] = this.label; |
281 | sb[sb.length] = '</a>'; |
282 | sb[sb.length] = '</td>'; |
283 | sb[sb.length] = '</tr>'; |
284 | sb[sb.length] = '</table>'; |
285 | |
286 | return sb.join(""); |
287 | |
288 | }, |
289 | |
290 | toString: function() { |
291 | return "TaskNode (" + this.index + ") " + this.label; |
292 | } |
293 | |
294 | }); |
view plain | print | ? |
INFO0ms (+0) 11:56:22 AM:global
Logger initialized
Copyright © 2008 Yahoo! Inc. All rights reserved.
Privacy Policy - Terms of Service - Copyright Policy - Job Openings