|
1 |
|
2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> |
|
3 <html> |
|
4 <head> |
|
5 <title>YUI Library Examples: Widget: Extending the base widget class</title> |
|
6 <meta http-equiv="content-type" content="text/html; charset=utf-8"> |
|
7 <link rel="stylesheet" type="text/css" href="../../assets/yui.css" > |
|
8 |
|
9 <style> |
|
10 /*Supplemental CSS for the YUI distribution*/ |
|
11 #custom-doc { width: 95%; min-width: 950px; } |
|
12 #pagetitle {background-image: url(../../assets/bg_hd.gif);} |
|
13 /* #pagetitle h1 {background-image: url(../../assets/title_h_bg.gif);}*/ |
|
14 </style> |
|
15 |
|
16 <link rel="stylesheet" type="text/css" href="../../assets/dpSyntaxHighlighter.css"> |
|
17 <link type="text/css" rel="stylesheet" href="../../build/cssfonts/fonts-min.css" /> |
|
18 <script type="text/javascript" src="../../build/yui/yui-min.js"></script> |
|
19 <style type="text/css"> |
|
20 |
|
21 .yui-spinner-hidden { |
|
22 display:none; |
|
23 } |
|
24 |
|
25 .yui-spinner { |
|
26 display:-moz-inline-stack; |
|
27 display:inline-block; |
|
28 zoom:1; |
|
29 *display:inline; |
|
30 vertical-align:middle; |
|
31 } |
|
32 |
|
33 .yui-spinner-content { |
|
34 padding:1px; |
|
35 position:relative; |
|
36 } |
|
37 |
|
38 .yui-spinner-value { |
|
39 width:2em; |
|
40 height:1.5em; |
|
41 text-align:right; |
|
42 margin-right:22px; |
|
43 vertical-align:top; |
|
44 border:1px solid #000; |
|
45 padding:2px; |
|
46 } |
|
47 |
|
48 .yui-spinner-increment, .yui-spinner-decrement { |
|
49 position:absolute; |
|
50 height:1em; |
|
51 width:22px; |
|
52 overflow:hidden; |
|
53 text-indent:-10em; |
|
54 border:1px solid #999; |
|
55 margin:0; |
|
56 padding:0px; |
|
57 } |
|
58 |
|
59 .yui-spinner-increment { |
|
60 top:1px; |
|
61 *top:2px; |
|
62 right:1px; |
|
63 background:#ddd url(assets/arrows.png) no-repeat 50% 0px; |
|
64 } |
|
65 |
|
66 .yui-spinner-decrement { |
|
67 bottom:1px; |
|
68 *bottom:2px; |
|
69 right:1px; |
|
70 background:#ddd url(assets/arrows.png) no-repeat 50% -20px; |
|
71 } |
|
72 |
|
73 #widget-extend-example { |
|
74 padding:5px; |
|
75 } |
|
76 |
|
77 #widget-extend-example .hint { |
|
78 margin-top:10px; |
|
79 font-size:85%; |
|
80 color:#00a; |
|
81 } |
|
82 |
|
83 </style> |
|
84 </head> |
|
85 <body id="yahoo-com" class=" yui-skin-sam"> |
|
86 <div id="custom-doc" class="yui-t2"> |
|
87 <div id="hd"> |
|
88 <div id="ygunav"> |
|
89 <p> |
|
90 <em> |
|
91 <a href="http://developer.yahoo.com/yui/3/">YUI 3.x Home</a> <i> - </i> |
|
92 </em> |
|
93 </p> |
|
94 <form action="http://search.yahoo.com/search" id="sitesearchform"> |
|
95 <input name="vs" type="hidden" value="developer.yahoo.com"> |
|
96 <input name="vs" type="hidden" value="yuiblog.com"> |
|
97 <div id="sitesearch"> |
|
98 <label for="searchinput">Site Search (YDN & YUIBlog): </label> |
|
99 <input type="text" id="searchinput" name="p"> |
|
100 <input type="submit" value="Search" id="searchsubmit" class="ygbt"> |
|
101 </div> |
|
102 </form> |
|
103 </div> |
|
104 <div id="ygma"><a href="../../"><img src="../../assets/logo.gif" border="0" width="200" height="93"></a></div> |
|
105 <div id="pagetitle"><h1>YUI Library Examples: Widget: Extending the base widget class</h1></div> |
|
106 </div> |
|
107 <div id="bd"> |
|
108 |
|
109 |
|
110 <div id="yui-main"> |
|
111 <div class="yui-b"> |
|
112 <div class="yui-ge"> |
|
113 <div class="yui-u first example" id="main"> |
|
114 |
|
115 <h2>Widget: Extending the base widget class</h2> |
|
116 |
|
117 <div id="example" class="promo"> |
|
118 <div class="example-intro"> |
|
119 This example shows how to extend the base <code>Widget</code> class to create a simple, re-usable spinner control. The <code>Spinner</code> class created in the example is not intended to be a fully featured spinner. It is used here as a concrete example, to convey some of the key concepts to keep in mind when extending the <code>Widget</code> class. |
|
120 </div> |
|
121 |
|
122 <div class="module example-container "> |
|
123 <div class="hd exampleHd"> |
|
124 <p class="newWindowButton yui-skin-sam"> |
|
125 <a href="widget-extend_clean.html" target="_blank">View example in new window.</a> |
|
126 </p> |
|
127 </div> <div id="example-canvas" class="bd"> |
|
128 |
|
129 |
|
130 <!--BEGIN SOURCE CODE FOR EXAMPLE =============================== --> |
|
131 |
|
132 <div id="widget-extend-example"> |
|
133 A basic spinner widget: <div id="numberField"><input type="text" class="yui-spinner-value" value="20" /></div> |
|
134 <p class="hint">Click the buttons, or the arrow up/down and page up/down keys on your keyboard to change the spinner's value</p> |
|
135 </div> |
|
136 |
|
137 <script type="text/javascript"> |
|
138 YUI({base:"../../build/", timeout: 10000}).use("event-key", "widget", function(Y) { |
|
139 |
|
140 var Lang = Y.Lang, |
|
141 Widget = Y.Widget, |
|
142 Node = Y.Node; |
|
143 |
|
144 /* Spinner class constructor */ |
|
145 function Spinner(config) { |
|
146 Spinner.superclass.constructor.apply(this, arguments); |
|
147 } |
|
148 |
|
149 /* |
|
150 * Required NAME static field, to identify the Widget class and |
|
151 * used as an event prefix, to generate class names etc. (set to the |
|
152 * class name in camel case). |
|
153 */ |
|
154 Spinner.NAME = "spinner"; |
|
155 |
|
156 /* |
|
157 * The attribute configuration for the Spinner widget. Attributes can be |
|
158 * defined with default values, get/set functions and validator functions |
|
159 * as with any other class extending Base. |
|
160 */ |
|
161 Spinner.ATTRS = { |
|
162 // The minimum value for the spinner. |
|
163 min : { |
|
164 value:0 |
|
165 }, |
|
166 |
|
167 // The maximum value for the spinner. |
|
168 max : { |
|
169 value:100 |
|
170 }, |
|
171 |
|
172 // The current value of the spinner. |
|
173 value : { |
|
174 value:0, |
|
175 validator: function(val) { |
|
176 return this._validateValue(val); |
|
177 } |
|
178 }, |
|
179 |
|
180 // Amount to increment/decrement the spinner when the buttons or arrow up/down keys are pressed. |
|
181 minorStep : { |
|
182 value:1 |
|
183 }, |
|
184 |
|
185 // Amount to increment/decrement the spinner when the page up/down keys are pressed. |
|
186 majorStep : { |
|
187 value:10 |
|
188 }, |
|
189 |
|
190 // The localizable strings for the spinner. This attribute is |
|
191 // defined by the base Widget class but has an empty value. The |
|
192 // spinner is simply providing a default value for the attribute. |
|
193 strings: { |
|
194 value: { |
|
195 tooltip: "Press the arrow up/down keys for minor increments, page up/down for major increments.", |
|
196 increment: "Increment", |
|
197 decrement: "Decrement" |
|
198 } |
|
199 } |
|
200 }; |
|
201 |
|
202 /* Static constant used to identify the classname applied to the spinners value field */ |
|
203 Spinner.INPUT_CLASS = Y.ClassNameManager.getClassName(Spinner.NAME, "value"); |
|
204 |
|
205 /* Static constants used to define the markup templates used to create Spinner DOM elements */ |
|
206 Spinner.INPUT_TEMPLATE = '<input type="text" class="' + Spinner.INPUT_CLASS + '">'; |
|
207 Spinner.BTN_TEMPLATE = '<button type="button"></button>'; |
|
208 |
|
209 /* |
|
210 * The HTML_PARSER static constant is used by the Widget base class to populate |
|
211 * the configuration for the spinner instance from markup already on the page. |
|
212 * |
|
213 * The Spinner class attempts to set the value of the spinner widget if it |
|
214 * finds the appropriate input element on the page. |
|
215 */ |
|
216 Spinner.HTML_PARSER = { |
|
217 value: function (contentBox) { |
|
218 var node = contentBox.one("." + Spinner.INPUT_CLASS); |
|
219 return (node) ? parseInt(node.get("value")) : null; |
|
220 } |
|
221 }; |
|
222 |
|
223 /* Spinner extends the base Widget class */ |
|
224 Y.extend(Spinner, Widget, { |
|
225 |
|
226 /* |
|
227 * initializer is part of the lifecycle introduced by |
|
228 * the Widget class. It is invoked during construction, |
|
229 * and can be used to setup instance specific state. |
|
230 * |
|
231 * The Spinner class does not need to perform anything |
|
232 * specific in this method, but it is left in as an example. |
|
233 */ |
|
234 initializer: function() { |
|
235 // Not doing anything special during initialization |
|
236 }, |
|
237 |
|
238 /* |
|
239 * destructor is part of the lifecycle introduced by |
|
240 * the Widget class. It is invoked during destruction, |
|
241 * and can be used to cleanup instance specific state. |
|
242 * |
|
243 * The spinner cleans up any node references it's holding |
|
244 * onto. The Widget classes destructor will purge the |
|
245 * widget's bounding box of event listeners, so spinner |
|
246 * only needs to clean up listeners it attaches outside of |
|
247 * the bounding box. |
|
248 */ |
|
249 destructor : function() { |
|
250 this._documentMouseUpHandle.detach(); |
|
251 |
|
252 this.inputNode = null; |
|
253 this.incrementNode = null; |
|
254 this.decrementNode = null; |
|
255 }, |
|
256 |
|
257 /* |
|
258 * renderUI is part of the lifecycle introduced by the |
|
259 * Widget class. Widget's renderer method invokes: |
|
260 * |
|
261 * renderUI() |
|
262 * bindUI() |
|
263 * syncUI() |
|
264 * |
|
265 * renderUI is intended to be used by the Widget subclass |
|
266 * to create or insert new elements into the DOM. |
|
267 * |
|
268 * For spinner the method adds the input (if it's not already |
|
269 * present in the markup), and creates the inc/dec buttons |
|
270 */ |
|
271 renderUI : function() { |
|
272 this._renderInput(); |
|
273 this._renderButtons(); |
|
274 }, |
|
275 |
|
276 /* |
|
277 * bindUI is intended to be used by the Widget subclass |
|
278 * to bind any event listeners which will drive the Widget UI. |
|
279 * |
|
280 * It will generally bind event listeners for attribute change |
|
281 * events, to update the state of the rendered UI in response |
|
282 * to attribute value changes, and also attach any DOM events, |
|
283 * to activate the UI. |
|
284 * |
|
285 * For spinner, the method: |
|
286 * |
|
287 * - Sets up the attribute change listener for the "value" attribute |
|
288 * |
|
289 * - Binds key listeners for the arrow/page keys |
|
290 * - Binds mouseup/down listeners on the boundingBox, document respectively. |
|
291 * - Binds a simple change listener on the input box. |
|
292 */ |
|
293 bindUI : function() { |
|
294 this.after("valueChange", this._afterValueChange); |
|
295 |
|
296 var boundingBox = this.get("boundingBox"); |
|
297 |
|
298 // Looking for a key event which will fire continously across browsers while the key is held down. 38, 40 = arrow up/down, 33, 34 = page up/down |
|
299 var keyEventSpec = (!Y.UA.opera) ? "down:" : "press:"; |
|
300 keyEventSpec += "38, 40, 33, 34"; |
|
301 |
|
302 Y.on("key", Y.bind(this._onDirectionKey, this), boundingBox, keyEventSpec); |
|
303 Y.on("mousedown", Y.bind(this._onMouseDown, this), boundingBox); |
|
304 this._documentMouseUpHandle = Y.on("mouseup", Y.bind(this._onDocMouseUp, this), boundingBox.get("ownerDocument")); |
|
305 |
|
306 Y.on("change", Y.bind(this._onInputChange, this), this.inputNode); |
|
307 }, |
|
308 |
|
309 /* |
|
310 * syncUI is intended to be used by the Widget subclass to |
|
311 * update the UI to reflect the current state of the widget. |
|
312 * |
|
313 * For spinner, the method sets the value of the input field, |
|
314 * to match the current state of the value attribute. |
|
315 */ |
|
316 syncUI : function() { |
|
317 this._uiSetValue(this.get("value")); |
|
318 }, |
|
319 |
|
320 /* |
|
321 * Creates the input control for the spinner and adds it to |
|
322 * the widget's content box, if not already in the markup. |
|
323 */ |
|
324 _renderInput : function() { |
|
325 var contentBox = this.get("contentBox"), |
|
326 input = contentBox.one("." + Spinner.INPUT_CLASS), |
|
327 strings = this.get("strings"); |
|
328 |
|
329 if (!input) { |
|
330 input = Node.create(Spinner.INPUT_TEMPLATE); |
|
331 contentBox.appendChild(input); |
|
332 } |
|
333 |
|
334 input.set("title", strings.tooltip); |
|
335 this.inputNode = input; |
|
336 }, |
|
337 |
|
338 /* |
|
339 * Creates the button controls for the spinner and add them to |
|
340 * the widget's content box, if not already in the markup. |
|
341 */ |
|
342 _renderButtons : function() { |
|
343 var contentBox = this.get("contentBox"), |
|
344 strings = this.get("strings"); |
|
345 |
|
346 var inc = this._createButton(strings.increment, this.getClassName("increment")); |
|
347 var dec = this._createButton(strings.decrement, this.getClassName("decrement")); |
|
348 |
|
349 this.incrementNode = contentBox.appendChild(inc); |
|
350 this.decrementNode = contentBox.appendChild(dec); |
|
351 }, |
|
352 |
|
353 /* |
|
354 * Utility method, to create a spinner button |
|
355 */ |
|
356 _createButton : function(text, className) { |
|
357 |
|
358 var btn = Y.Node.create(Spinner.BTN_TEMPLATE); |
|
359 btn.set("innerHTML", text); |
|
360 btn.set("title", text); |
|
361 btn.addClass(className); |
|
362 |
|
363 return btn; |
|
364 }, |
|
365 |
|
366 /* |
|
367 * Bounding box mouse down handler. Will determine if the mouse down |
|
368 * is on one of the spinner buttons, and increment/decrement the value |
|
369 * accordingly. |
|
370 * |
|
371 * The method also sets up a timer, to support the user holding the mouse |
|
372 * down on the spinner buttons. The timer is cleared when a mouse up event |
|
373 * is detected. |
|
374 */ |
|
375 _onMouseDown : function(e) { |
|
376 var node = e.target, |
|
377 dir, |
|
378 handled = false, |
|
379 currVal = this.get("value"), |
|
380 minorStep = this.get("minorStep"); |
|
381 |
|
382 if (node.hasClass(this.getClassName("increment"))) { |
|
383 this.set("value", currVal + minorStep); |
|
384 dir = 1; |
|
385 handled = true; |
|
386 } else if (node.hasClass(this.getClassName("decrement"))) { |
|
387 this.set("value", currVal - minorStep); |
|
388 dir = -1; |
|
389 handled = true; |
|
390 } |
|
391 |
|
392 if (handled) { |
|
393 this._setMouseDownTimers(dir, minorStep); |
|
394 } |
|
395 }, |
|
396 |
|
397 /* |
|
398 * Document mouse up handler. Clears the timers supporting |
|
399 * the "mouse held down" behavior. |
|
400 */ |
|
401 _onDocMouseUp : function(e) { |
|
402 this._clearMouseDownTimers(); |
|
403 }, |
|
404 |
|
405 /* |
|
406 * Bounding box Arrow up/down, Page up/down key listener. |
|
407 * |
|
408 * Increments/Decrement the spinner value, based on the key pressed. |
|
409 */ |
|
410 _onDirectionKey : function(e) { |
|
411 |
|
412 e.preventDefault(); |
|
413 |
|
414 var currVal = this.get("value"), |
|
415 newVal = currVal, |
|
416 minorStep = this.get("minorStep"), |
|
417 majorStep = this.get("majorStep"); |
|
418 |
|
419 switch (e.charCode) { |
|
420 case 38: |
|
421 newVal += minorStep; |
|
422 break; |
|
423 case 40: |
|
424 newVal -= minorStep; |
|
425 break; |
|
426 case 33: |
|
427 newVal += majorStep; |
|
428 newVal = Math.min(newVal, this.get("max")); |
|
429 break; |
|
430 case 34: |
|
431 newVal -= majorStep; |
|
432 newVal = Math.max(newVal, this.get("min")); |
|
433 break; |
|
434 } |
|
435 |
|
436 if (newVal !== currVal) { |
|
437 this.set("value", newVal); |
|
438 } |
|
439 }, |
|
440 |
|
441 /* |
|
442 * Simple change handler, to make sure user does not input an invalid value |
|
443 */ |
|
444 _onInputChange : function(e) { |
|
445 if (!this._validateValue(this.inputNode.get("value"))) { |
|
446 this.syncUI(); |
|
447 } |
|
448 }, |
|
449 |
|
450 /* |
|
451 * Initiates mouse down timers, to increment slider, while mouse button |
|
452 * is held down |
|
453 */ |
|
454 _setMouseDownTimers : function(dir, step) { |
|
455 this._mouseDownTimer = Y.later(500, this, function() { |
|
456 this._mousePressTimer = Y.later(100, this, function() { |
|
457 this.set("value", this.get("value") + (dir * step)); |
|
458 }, null, true) |
|
459 }); |
|
460 }, |
|
461 |
|
462 /* |
|
463 * Clears timers used to support the "mouse held down" behavior |
|
464 */ |
|
465 _clearMouseDownTimers : function() { |
|
466 if (this._mouseDownTimer) { |
|
467 this._mouseDownTimer.cancel(); |
|
468 this._mouseDownTimer = null; |
|
469 } |
|
470 if (this._mousePressTimer) { |
|
471 this._mousePressTimer.cancel(); |
|
472 this._mousePressTimer = null; |
|
473 } |
|
474 }, |
|
475 |
|
476 /* |
|
477 * value attribute change listener. Updates the |
|
478 * value in the rendered input box, whenever the |
|
479 * attribute value changes. |
|
480 */ |
|
481 _afterValueChange : function(e) { |
|
482 this._uiSetValue(e.newVal); |
|
483 }, |
|
484 |
|
485 /* |
|
486 * Updates the value of the input box to reflect |
|
487 * the value passed in |
|
488 */ |
|
489 _uiSetValue : function(val) { |
|
490 this.inputNode.set("value", val); |
|
491 }, |
|
492 |
|
493 /* |
|
494 * value attribute default validator. Verifies that |
|
495 * the value being set lies between the min/max value |
|
496 */ |
|
497 _validateValue: function(val) { |
|
498 var min = this.get("min"), |
|
499 max = this.get("max"); |
|
500 |
|
501 return (Lang.isNumber(val) && val >= min && val <= max); |
|
502 } |
|
503 }); |
|
504 |
|
505 // Create a new Spinner instance, drawing it's |
|
506 // starting value from an input field already on the |
|
507 // page (contained in the #numberField content box) |
|
508 var spinner = new Spinner({ |
|
509 contentBox: "#numberField", |
|
510 max:100, |
|
511 min:0 |
|
512 }); |
|
513 spinner.render(); |
|
514 spinner.focus(); |
|
515 }); |
|
516 </script> |
|
517 |
|
518 <!--END SOURCE CODE FOR EXAMPLE =============================== --> |
|
519 |
|
520 |
|
521 </div> |
|
522 </div> |
|
523 </div> |
|
524 |
|
525 <h3>Extending The <code>Widget</code> Class</h3> |
|
526 |
|
527 <h4>Basic Class Structure</h4> |
|
528 |
|
529 <p>Widgets classes follow the general pattern implemented by the <code>Spinner</code> class, shown in the code snippet below. The basic pattern for setting up a new widget class involves:</p> |
|
530 |
|
531 <ol> |
|
532 <li>Defining the constructor function for the new widget class, which invokes the superclass constructor to kick of the initialization chain <em>(line 2)</em></li> |
|
533 <li>Defining the static <code>NAME</code> property for the class, which is normally the class name in camel case, and is used to prefix events and CSS classes fired/created by the class <em>(line 11)</em></li> |
|
534 <li>Defining the static <code>ATTRS</code> property for the class, which defines the set of attribute which the class will introduce, in addition to the superclass attributes <em>(line 18-57)</em></li> |
|
535 <li>Extending the <code>Widget</code> class, and adding/over-riding any prototype properties/methods <em>(line 59)</em></li> |
|
536 </ol> |
|
537 |
|
538 <div id="syntax1" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/* Spinner class constructor */</span></div></li><li class="li1"><div class="de1"><span class="kw2">function</span> Spinner<span class="br0">(</span>config<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> Spinner.<span class="me1">superclass</span>.<span class="me1">constructor</span>.<span class="me1">apply</span><span class="br0">(</span><span class="kw1">this</span><span class="sy0">,</span> arguments<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/* </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * Required NAME static field, to identify the Widget class and </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * used as an event prefix, to generate class names etc. (set to the </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * class name in camel case). </span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">Spinner.<span class="kw3">NAME</span> <span class="sy0">=</span> <span class="st0">"spinner"</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * The attribute configuration for the Spinner widget. Attributes can be</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * defined with default values, get/set functions and validator functions</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * as with any other class extending Base.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">Spinner.<span class="me1">ATTRS</span> <span class="sy0">=</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="co1">// The minimum value for the spinner.</span></div></li><li class="li2"><div class="de2"> min <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> value<span class="sy0">:</span><span class="nu0">0</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// The maximum value for the spinner.</span></div></li><li class="li2"><div class="de2"> max <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> value<span class="sy0">:</span><span class="nu0">100</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// The current value of the spinner.</span></div></li><li class="li2"><div class="de2"> value <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> value<span class="sy0">:</span><span class="nu0">0</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> validator<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>val<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">return</span> <span class="kw1">this</span>._validateValue<span class="br0">(</span>val<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li2"><div class="de2"> <span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// Amount to increment/decrement the spinner when the buttons, </span></div></li><li class="li1"><div class="de1"> <span class="co1">// or arrow up/down keys are pressed.</span></div></li><li class="li1"><div class="de1"> minorStep <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> value<span class="sy0">:</span><span class="nu0">1</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// Amount to increment/decrement the spinner when the page up/down keys are pressed.</span></div></li><li class="li1"><div class="de1"> majorStep <span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> value<span class="sy0">:</span><span class="nu0">10</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// The localizable strings for the spinner. This attribute is </span></div></li><li class="li1"><div class="de1"> <span class="co1">// defined by the base Widget class but has an empty value. The</span></div></li><li class="li2"><div class="de2"> <span class="co1">// spinner is simply providing a default value for the attribute.</span></div></li><li class="li1"><div class="de1"> strings<span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> value<span class="sy0">:</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> tooltip<span class="sy0">:</span> <span class="st0">"Press the arrow up/down keys for minor increments, <span class="es0">\ </span></span></div></li><li class="li1"><div class="de1"><span class="st0"> page up/down for major increments."</span><span class="sy0">,</span></div></li><li class="li2"><div class="de2"> increment<span class="sy0">:</span> <span class="st0">"Increment"</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> decrement<span class="sy0">:</span> <span class="st0">"Decrement"</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1">Y.<span class="me1">extend</span><span class="br0">(</span>Spinner<span class="sy0">,</span> Widget<span class="sy0">,</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="co1">// Methods/properties to add to the prototype of the new class</span></div></li><li class="li1"><div class="de1"> ...</div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="coMULTI">/* Spinner class constructor */</span> |
|
539 <span class="kw2">function</span> Spinner<span class="br0">(</span>config<span class="br0">)</span> <span class="br0">{</span> |
|
540 Spinner.<span class="me1">superclass</span>.<span class="me1">constructor</span>.<span class="me1">apply</span><span class="br0">(</span><span class="kw1">this</span><span class="sy0">,</span> arguments<span class="br0">)</span><span class="sy0">;</span> |
|
541 <span class="br0">}</span> |
|
542 |
|
543 <span class="coMULTI">/* |
|
544 * Required NAME static field, to identify the Widget class and |
|
545 * used as an event prefix, to generate class names etc. (set to the |
|
546 * class name in camel case). |
|
547 */</span> |
|
548 Spinner.<span class="kw3">NAME</span> <span class="sy0">=</span> <span class="st0">"spinner"</span><span class="sy0">;</span> |
|
549 |
|
550 <span class="coMULTI">/* |
|
551 * The attribute configuration for the Spinner widget. Attributes can be |
|
552 * defined with default values, get/set functions and validator functions |
|
553 * as with any other class extending Base. |
|
554 */</span> |
|
555 Spinner.<span class="me1">ATTRS</span> <span class="sy0">=</span> <span class="br0">{</span> |
|
556 <span class="co1">// The minimum value for the spinner.</span> |
|
557 min <span class="sy0">:</span> <span class="br0">{</span> |
|
558 value<span class="sy0">:</span><span class="nu0">0</span> |
|
559 <span class="br0">}</span><span class="sy0">,</span> |
|
560 |
|
561 <span class="co1">// The maximum value for the spinner.</span> |
|
562 max <span class="sy0">:</span> <span class="br0">{</span> |
|
563 value<span class="sy0">:</span><span class="nu0">100</span> |
|
564 <span class="br0">}</span><span class="sy0">,</span> |
|
565 |
|
566 <span class="co1">// The current value of the spinner.</span> |
|
567 value <span class="sy0">:</span> <span class="br0">{</span> |
|
568 value<span class="sy0">:</span><span class="nu0">0</span><span class="sy0">,</span> |
|
569 validator<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>val<span class="br0">)</span> <span class="br0">{</span> |
|
570 <span class="kw1">return</span> <span class="kw1">this</span>._validateValue<span class="br0">(</span>val<span class="br0">)</span><span class="sy0">;</span> |
|
571 <span class="br0">}</span> |
|
572 <span class="br0">}</span><span class="sy0">,</span> |
|
573 |
|
574 <span class="co1">// Amount to increment/decrement the spinner when the buttons, </span> |
|
575 <span class="co1">// or arrow up/down keys are pressed.</span> |
|
576 minorStep <span class="sy0">:</span> <span class="br0">{</span> |
|
577 value<span class="sy0">:</span><span class="nu0">1</span> |
|
578 <span class="br0">}</span><span class="sy0">,</span> |
|
579 |
|
580 <span class="co1">// Amount to increment/decrement the spinner when the page up/down keys are pressed.</span> |
|
581 majorStep <span class="sy0">:</span> <span class="br0">{</span> |
|
582 value<span class="sy0">:</span><span class="nu0">10</span> |
|
583 <span class="br0">}</span><span class="sy0">,</span> |
|
584 |
|
585 <span class="co1">// The localizable strings for the spinner. This attribute is </span> |
|
586 <span class="co1">// defined by the base Widget class but has an empty value. The</span> |
|
587 <span class="co1">// spinner is simply providing a default value for the attribute.</span> |
|
588 strings<span class="sy0">:</span> <span class="br0">{</span> |
|
589 value<span class="sy0">:</span> <span class="br0">{</span> |
|
590 tooltip<span class="sy0">:</span> <span class="st0">"Press the arrow up/down keys for minor increments, <span class="es0">\ </span> |
|
591 page up/down for major increments."</span><span class="sy0">,</span> |
|
592 increment<span class="sy0">:</span> <span class="st0">"Increment"</span><span class="sy0">,</span> |
|
593 decrement<span class="sy0">:</span> <span class="st0">"Decrement"</span> |
|
594 <span class="br0">}</span> |
|
595 <span class="br0">}</span> |
|
596 <span class="br0">}</span><span class="sy0">;</span> |
|
597 |
|
598 Y.<span class="me1">extend</span><span class="br0">(</span>Spinner<span class="sy0">,</span> Widget<span class="sy0">,</span> <span class="br0">{</span> |
|
599 <span class="co1">// Methods/properties to add to the prototype of the new class</span> |
|
600 ... |
|
601 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></pre></div><textarea id="syntax1-plain">/* Spinner class constructor */ |
|
602 function Spinner(config) { |
|
603 Spinner.superclass.constructor.apply(this, arguments); |
|
604 } |
|
605 |
|
606 /* |
|
607 * Required NAME static field, to identify the Widget class and |
|
608 * used as an event prefix, to generate class names etc. (set to the |
|
609 * class name in camel case). |
|
610 */ |
|
611 Spinner.NAME = "spinner"; |
|
612 |
|
613 /* |
|
614 * The attribute configuration for the Spinner widget. Attributes can be |
|
615 * defined with default values, get/set functions and validator functions |
|
616 * as with any other class extending Base. |
|
617 */ |
|
618 Spinner.ATTRS = { |
|
619 // The minimum value for the spinner. |
|
620 min : { |
|
621 value:0 |
|
622 }, |
|
623 |
|
624 // The maximum value for the spinner. |
|
625 max : { |
|
626 value:100 |
|
627 }, |
|
628 |
|
629 // The current value of the spinner. |
|
630 value : { |
|
631 value:0, |
|
632 validator: function(val) { |
|
633 return this._validateValue(val); |
|
634 } |
|
635 }, |
|
636 |
|
637 // Amount to increment/decrement the spinner when the buttons, |
|
638 // or arrow up/down keys are pressed. |
|
639 minorStep : { |
|
640 value:1 |
|
641 }, |
|
642 |
|
643 // Amount to increment/decrement the spinner when the page up/down keys are pressed. |
|
644 majorStep : { |
|
645 value:10 |
|
646 }, |
|
647 |
|
648 // The localizable strings for the spinner. This attribute is |
|
649 // defined by the base Widget class but has an empty value. The |
|
650 // spinner is simply providing a default value for the attribute. |
|
651 strings: { |
|
652 value: { |
|
653 tooltip: "Press the arrow up/down keys for minor increments, \ |
|
654 page up/down for major increments.", |
|
655 increment: "Increment", |
|
656 decrement: "Decrement" |
|
657 } |
|
658 } |
|
659 }; |
|
660 |
|
661 Y.extend(Spinner, Widget, { |
|
662 // Methods/properties to add to the prototype of the new class |
|
663 ... |
|
664 });</textarea></div> |
|
665 <p>Note that these steps are the same for any class which is derived from <a href="http://developer.yahoo.com/yui/3/base/"><code>Base</code></a>, nothing Widget specific is involved yet. |
|
666 Widget adds the concept of a rendered UI to the existing Base lifecycle (viz. init, destroy and attribute state configuration), which we'll see show up in Widget specific areas below.</p> |
|
667 |
|
668 <h4>The HTML_PARSER Property</h4> |
|
669 |
|
670 <p> |
|
671 The first Widget specific property <code>Spinner</code> implements is the static <a href="../../api/Widget.html#property_Widget.HTML_PARSER"><code>HTML_PARSER</code></a> property. It is used to set the initial widget configuration based on markup, providing basic progressive enhancement support. |
|
672 </p> |
|
673 <p> |
|
674 The value of the <code>HTML_PARSER</code> property is an object literal, where each property is a widget attribute name, and the value is either a selector string (if the attribute is a node reference) or a function which is executed to provide |
|
675 a value for the attribute from the markup on the page. Markup is essentially thought of as an additional data source for the user to set initial attribute values, outside of the configuration object passed to the constructor |
|
676 <em>(values passed to the constructor will take precedence over values picked up from markup)</em>. |
|
677 </p> |
|
678 |
|
679 <p>For <code>Spinner</code>, <code>HTML_PARSER</code> defines a function for the <code>value</code> attribute, which sets the initial value of the spinner based on an input field if present in the markup.</p> |
|
680 |
|
681 <div id="syntax2" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/* </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * The HTML_PARSER static constant is used by the Widget base class to populate </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * the configuration for the spinner instance from markup already on the page.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> *</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * The Spinner class attempts to set the value of the spinner widget if it</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * finds the appropriate input element on the page.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">Spinner.<span class="me1">HTML_PARSER</span> <span class="sy0">=</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> value<span class="sy0">:</span> <span class="kw2">function</span> <span class="br0">(</span>contentBox<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> <span class="kw2">var</span> node <span class="sy0">=</span> contentBox.<span class="me1">one</span><span class="br0">(</span><span class="st0">"."</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">return</span> <span class="br0">(</span>node<span class="br0">)</span> <span class="sy0">?</span> parseInt<span class="br0">(</span>node.<span class="me1">get</span><span class="br0">(</span><span class="st0">"value"</span><span class="br0">)</span><span class="br0">)</span> <span class="sy0">:</span> <span class="kw2">null</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="coMULTI">/* |
|
682 * The HTML_PARSER static constant is used by the Widget base class to populate |
|
683 * the configuration for the spinner instance from markup already on the page. |
|
684 * |
|
685 * The Spinner class attempts to set the value of the spinner widget if it |
|
686 * finds the appropriate input element on the page. |
|
687 */</span> |
|
688 Spinner.<span class="me1">HTML_PARSER</span> <span class="sy0">=</span> <span class="br0">{</span> |
|
689 value<span class="sy0">:</span> <span class="kw2">function</span> <span class="br0">(</span>contentBox<span class="br0">)</span> <span class="br0">{</span> |
|
690 <span class="kw2">var</span> node <span class="sy0">=</span> contentBox.<span class="me1">one</span><span class="br0">(</span><span class="st0">"."</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">)</span><span class="sy0">;</span> |
|
691 <span class="kw1">return</span> <span class="br0">(</span>node<span class="br0">)</span> <span class="sy0">?</span> parseInt<span class="br0">(</span>node.<span class="me1">get</span><span class="br0">(</span><span class="st0">"value"</span><span class="br0">)</span><span class="br0">)</span> <span class="sy0">:</span> <span class="kw2">null</span><span class="sy0">;</span> |
|
692 <span class="br0">}</span> |
|
693 <span class="br0">}</span><span class="sy0">;</span></pre></div><textarea id="syntax2-plain">/* |
|
694 * The HTML_PARSER static constant is used by the Widget base class to populate |
|
695 * the configuration for the spinner instance from markup already on the page. |
|
696 * |
|
697 * The Spinner class attempts to set the value of the spinner widget if it |
|
698 * finds the appropriate input element on the page. |
|
699 */ |
|
700 Spinner.HTML_PARSER = { |
|
701 value: function (contentBox) { |
|
702 var node = contentBox.one("." + Spinner.INPUT_CLASS); |
|
703 return (node) ? parseInt(node.get("value")) : null; |
|
704 } |
|
705 };</textarea></div> |
|
706 <h4>Lifecycle Methods: initializer, destructor</h4> |
|
707 |
|
708 <p>The <code>initializer</code> and <code>destructor</code> lifecycle methods are carried over from <code>Base</code>, and can be used to setup initial state during construction, and cleanup state during destruction respectively.</p> |
|
709 |
|
710 <p>For <code>Spinner</code>, there is nothing special we need to do in the <code>initializer</code> (attribute setup is already taken care of), but it's left in the example to round out the lifecycle discussion.</p> |
|
711 |
|
712 <p>The <code>destructor</code> takes care of detaching any event listeners <code>Spinner</code> adds outside of the bounding box (event listeners on/inside the bounding box are purged by <code>Widget</code>'s <code>destructor</code>).</p> |
|
713 |
|
714 <div id="syntax3" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * initializer is part of the lifecycle introduced by </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * the Widget class. It is invoked during construction,</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * and can be used to setup instance specific state.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * The Spinner class does not need to perform anything</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * specific in this method, but it is left in as an example.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">initializer<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>config<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> <span class="co1">// Not doing anything special during initialization</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * destructor is part of the lifecycle introduced by </span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * the Widget class. It is invoked during destruction,</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * and can be used to cleanup instance specific state.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * The spinner cleans up any node references it's holding</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * onto. The Widget classes destructor will purge the </span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * widget's bounding box of event listeners, so spinner </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * only needs to clean up listeners it attaches outside of </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * the bounding box.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">destructor <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>._documentMouseUpHandle.<span class="me1">detach</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">inputNode</span> <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">incrementNode</span> <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">decrementNode</span> <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="br0">}</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="coMULTI">/* |
|
715 * initializer is part of the lifecycle introduced by |
|
716 * the Widget class. It is invoked during construction, |
|
717 * and can be used to setup instance specific state. |
|
718 * |
|
719 * The Spinner class does not need to perform anything |
|
720 * specific in this method, but it is left in as an example. |
|
721 */</span> |
|
722 initializer<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>config<span class="br0">)</span> <span class="br0">{</span> |
|
723 <span class="co1">// Not doing anything special during initialization</span> |
|
724 <span class="br0">}</span><span class="sy0">,</span> |
|
725 |
|
726 <span class="coMULTI">/* |
|
727 * destructor is part of the lifecycle introduced by |
|
728 * the Widget class. It is invoked during destruction, |
|
729 * and can be used to cleanup instance specific state. |
|
730 * |
|
731 * The spinner cleans up any node references it's holding |
|
732 * onto. The Widget classes destructor will purge the |
|
733 * widget's bounding box of event listeners, so spinner |
|
734 * only needs to clean up listeners it attaches outside of |
|
735 * the bounding box. |
|
736 */</span> |
|
737 destructor <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> |
|
738 <span class="kw1">this</span>._documentMouseUpHandle.<span class="me1">detach</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
739 |
|
740 <span class="kw1">this</span>.<span class="me1">inputNode</span> <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span> |
|
741 <span class="kw1">this</span>.<span class="me1">incrementNode</span> <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span> |
|
742 <span class="kw1">this</span>.<span class="me1">decrementNode</span> <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span> |
|
743 <span class="br0">}</span></pre></div><textarea id="syntax3-plain">/* |
|
744 * initializer is part of the lifecycle introduced by |
|
745 * the Widget class. It is invoked during construction, |
|
746 * and can be used to setup instance specific state. |
|
747 * |
|
748 * The Spinner class does not need to perform anything |
|
749 * specific in this method, but it is left in as an example. |
|
750 */ |
|
751 initializer: function(config) { |
|
752 // Not doing anything special during initialization |
|
753 }, |
|
754 |
|
755 /* |
|
756 * destructor is part of the lifecycle introduced by |
|
757 * the Widget class. It is invoked during destruction, |
|
758 * and can be used to cleanup instance specific state. |
|
759 * |
|
760 * The spinner cleans up any node references it's holding |
|
761 * onto. The Widget classes destructor will purge the |
|
762 * widget's bounding box of event listeners, so spinner |
|
763 * only needs to clean up listeners it attaches outside of |
|
764 * the bounding box. |
|
765 */ |
|
766 destructor : function() { |
|
767 this._documentMouseUpHandle.detach(); |
|
768 |
|
769 this.inputNode = null; |
|
770 this.incrementNode = null; |
|
771 this.decrementNode = null; |
|
772 }</textarea></div> |
|
773 <h4>Rendering Lifecycle Methods: renderer, renderUI, bindUI, syncUI</h4> |
|
774 |
|
775 <p>Widget adds a <code>render</code> method to the <code>init</code> and <code>destroy</code> lifecycle methods provided by Base. The <code>init</code> and <code>destroy</code> methods invoke the corresponding <code>initializer</code> and <code>destructor</code> implementations for the widget. Similarly, the <code>render</code> method invokes the <code>renderer</code> implementation for the widget. Note that the <code>renderer</code> method is not chained automatically, unlike the <code>initializer</code> and <code>destructor</code> methods.</p> |
|
776 |
|
777 <p>The <code>Widget</code> class already provides a default <code>renderer</code> implementation, which invokes the following abstract methods in the order shown <em>(with their respective responsibilities)</em>:</p> |
|
778 |
|
779 <ol> |
|
780 <li><code>renderUI()</code> : responsible for creating/adding elements to the DOM to render the widget.</li> |
|
781 <li><code>bindUI()</code> : responsible for binding event listeners (both attribute change and DOM event listeners) to 'activate' the rendered UI.</li> |
|
782 <li><code>syncUI()</code> : responsible for updating the rendered UI based on the current state of the widget.</li> |
|
783 </ol> |
|
784 |
|
785 <p>Since the <code>Spinner</code> class has no need to modify the <code>Widget</code> <code>renderer</code> implementation, it simply implements the above 3 methods to handle the render phase:</p> |
|
786 |
|
787 <div id="syntax4" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * For spinner the method adds the input (if it's not already </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * present in the markup), and creates the increment/decrement buttons</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li2"><div class="de2">renderUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>._renderInput<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>._renderButtons<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * For spinner, the method:</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> *</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * - Sets up the attribute change listener for the "value" attribute</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> *</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * - Binds key listeners for the arrow/page keys</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * - Binds mouseup/down listeners on the boundingBox, document respectively.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * - Binds a simple change listener on the input box.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">bindUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"valueChange"</span><span class="sy0">,</span> <span class="kw1">this</span>._afterValueChange<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> boundingBox <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"boundingBox"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="co1">// Looking for a key event which will fire continuously across browsers </span></div></li><li class="li2"><div class="de2"> <span class="co1">// while the key is held down. 38, 40 = arrow up/down, 33, 34 = page up/down</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> keyEventSpec <span class="sy0">=</span> <span class="br0">(</span><span class="sy0">!</span>Y.<span class="me1">UA</span>.<span class="me1">opera</span><span class="br0">)</span> <span class="sy0">?</span> <span class="st0">"down:"</span> <span class="sy0">:</span> <span class="st0">"press:"</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> keyEventSpec <span class="sy0">+=</span> <span class="st0">"38, 40, 33, 34"</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"change"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onInputChange<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">inputNode</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"key"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onDirectionKey<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> boundingBox<span class="sy0">,</span> keyEventSpec<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"mousedown"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onMouseDown<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> boundingBox<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>._documentMouseUpHandle <span class="sy0">=</span> Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"mouseup"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onDocMouseUp<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> </div></li><li class="li1"><div class="de1"> boundingBox.<span class="me1">get</span><span class="br0">(</span><span class="st0">"ownerDocument"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * For spinner, the method sets the value of the input field,</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * to match the current state of the value attribute.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">syncUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>._uiSetValue<span class="br0">(</span><span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"value"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="coMULTI">/* |
|
788 * For spinner the method adds the input (if it's not already |
|
789 * present in the markup), and creates the increment/decrement buttons |
|
790 */</span> |
|
791 renderUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> |
|
792 <span class="kw1">this</span>._renderInput<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
793 <span class="kw1">this</span>._renderButtons<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
794 <span class="br0">}</span><span class="sy0">,</span> |
|
795 |
|
796 <span class="coMULTI">/* |
|
797 * For spinner, the method: |
|
798 * |
|
799 * - Sets up the attribute change listener for the "value" attribute |
|
800 * |
|
801 * - Binds key listeners for the arrow/page keys |
|
802 * - Binds mouseup/down listeners on the boundingBox, document respectively. |
|
803 * - Binds a simple change listener on the input box. |
|
804 */</span> |
|
805 bindUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> |
|
806 <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">(</span><span class="st0">"valueChange"</span><span class="sy0">,</span> <span class="kw1">this</span>._afterValueChange<span class="br0">)</span><span class="sy0">;</span> |
|
807 |
|
808 <span class="kw2">var</span> boundingBox <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"boundingBox"</span><span class="br0">)</span><span class="sy0">;</span> |
|
809 |
|
810 <span class="co1">// Looking for a key event which will fire continuously across browsers </span> |
|
811 <span class="co1">// while the key is held down. 38, 40 = arrow up/down, 33, 34 = page up/down</span> |
|
812 <span class="kw2">var</span> keyEventSpec <span class="sy0">=</span> <span class="br0">(</span><span class="sy0">!</span>Y.<span class="me1">UA</span>.<span class="me1">opera</span><span class="br0">)</span> <span class="sy0">?</span> <span class="st0">"down:"</span> <span class="sy0">:</span> <span class="st0">"press:"</span><span class="sy0">;</span> |
|
813 keyEventSpec <span class="sy0">+=</span> <span class="st0">"38, 40, 33, 34"</span><span class="sy0">;</span> |
|
814 |
|
815 |
|
816 Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"change"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onInputChange<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">inputNode</span><span class="br0">)</span><span class="sy0">;</span> |
|
817 Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"key"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onDirectionKey<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> boundingBox<span class="sy0">,</span> keyEventSpec<span class="br0">)</span><span class="sy0">;</span> |
|
818 Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"mousedown"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onMouseDown<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> boundingBox<span class="br0">)</span><span class="sy0">;</span> |
|
819 <span class="kw1">this</span>._documentMouseUpHandle <span class="sy0">=</span> Y.<span class="me1">on</span><span class="br0">(</span><span class="st0">"mouseup"</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">(</span><span class="kw1">this</span>._onDocMouseUp<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">)</span><span class="sy0">,</span> |
|
820 boundingBox.<span class="me1">get</span><span class="br0">(</span><span class="st0">"ownerDocument"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span> |
|
821 <span class="br0">}</span><span class="sy0">,</span> |
|
822 |
|
823 <span class="coMULTI">/* |
|
824 * For spinner, the method sets the value of the input field, |
|
825 * to match the current state of the value attribute. |
|
826 */</span> |
|
827 syncUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> |
|
828 <span class="kw1">this</span>._uiSetValue<span class="br0">(</span><span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"value"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span> |
|
829 <span class="br0">}</span></pre></div><textarea id="syntax4-plain">/* |
|
830 * For spinner the method adds the input (if it's not already |
|
831 * present in the markup), and creates the increment/decrement buttons |
|
832 */ |
|
833 renderUI : function() { |
|
834 this._renderInput(); |
|
835 this._renderButtons(); |
|
836 }, |
|
837 |
|
838 /* |
|
839 * For spinner, the method: |
|
840 * |
|
841 * - Sets up the attribute change listener for the "value" attribute |
|
842 * |
|
843 * - Binds key listeners for the arrow/page keys |
|
844 * - Binds mouseup/down listeners on the boundingBox, document respectively. |
|
845 * - Binds a simple change listener on the input box. |
|
846 */ |
|
847 bindUI : function() { |
|
848 this.after("valueChange", this._afterValueChange); |
|
849 |
|
850 var boundingBox = this.get("boundingBox"); |
|
851 |
|
852 // Looking for a key event which will fire continuously across browsers |
|
853 // while the key is held down. 38, 40 = arrow up/down, 33, 34 = page up/down |
|
854 var keyEventSpec = (!Y.UA.opera) ? "down:" : "press:"; |
|
855 keyEventSpec += "38, 40, 33, 34"; |
|
856 |
|
857 |
|
858 Y.on("change", Y.bind(this._onInputChange, this), this.inputNode); |
|
859 Y.on("key", Y.bind(this._onDirectionKey, this), boundingBox, keyEventSpec); |
|
860 Y.on("mousedown", Y.bind(this._onMouseDown, this), boundingBox); |
|
861 this._documentMouseUpHandle = Y.on("mouseup", Y.bind(this._onDocMouseUp, this), |
|
862 boundingBox.get("ownerDocument")); |
|
863 }, |
|
864 |
|
865 /* |
|
866 * For spinner, the method sets the value of the input field, |
|
867 * to match the current state of the value attribute. |
|
868 */ |
|
869 syncUI : function() { |
|
870 this._uiSetValue(this.get("value")); |
|
871 }</textarea></div> |
|
872 <h5>A Note On Key Event Listeners</h5> |
|
873 |
|
874 <p>The <code>Spinner</code> uses Event's <code>"key"</code> support, to set up a listener for arrow up/down and page up/down keys on the spinner's bounding box (line 30).</p> |
|
875 |
|
876 <p>Event's <code>"key"</code> support allows <code>Spinner</code> to define a single listener, which is only invoked for the key specification provided. The key specification in the above use case is <code>"down:38, 40, 33, 34"</code> for most browsers, indicating that |
|
877 the <code>_onDirectionKey</code> method should only be called if the bounding box receives a keydown event with a character code which is either 38, 40, 33 or 34. <code>"key"</code> specifications can also contain more <a href="../../api/YUI.html#event_key">advanced filter criteria</a>, involving modifiers such as CTRL and SHIFT.</p> |
|
878 |
|
879 <p>For the Spinner widget, we're looking for a key event which fires repeatedly while the key is held down. This differs for Opera, so we need to fork for the key event we're interested in. Future versions of <code>"key"</code> support will aim to provide this type of higher level cross-browser abstraction also.</p> |
|
880 |
|
881 <h4>Attribute Supporting Methods</h4> |
|
882 |
|
883 <p>Since all widgets are attribute driven, they all follow a pretty similar pattern when it comes to how those attributes are used. For a given attribute, widgets will generally have:</p> |
|
884 <ul> |
|
885 <li>A prototype method to listen for changes in the attribute</li> |
|
886 <li>A prototype method to update the state of the rendered UI, to reflect the value of an attribute.</li> |
|
887 <li>A prototype method used to set/get/validate the attribute.</li> |
|
888 </ul> |
|
889 |
|
890 <p>These methods are kept on the prototype to facilitate customization at any of the levels - event handling, ui updates, set/get/validation logic.</p> |
|
891 |
|
892 <p>For <code>Spinner</code>, these corresponding methods for the <code>value</code> attribute are: <code>_afterValueChange</code>, <code>_uiSetValue</code> and <code>_validateValue</code>:</p> |
|
893 |
|
894 <div id="syntax5" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * value attribute change listener. Updates the </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * value in the rendered input box, whenever the </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * attribute value changes.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">_afterValueChange <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>._uiSetValue<span class="br0">(</span>e.<span class="me1">newVal</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * Updates the value of the input box to reflect </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * the value passed in</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">_uiSetValue <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>val<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>.<span class="me1">inputNode</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> val<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * value attribute default validator. Verifies that</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * the value being set lies between the min/max value</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">_validateValue<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>val<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> min <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"min"</span><span class="br0">)</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> max <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"max"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"> <span class="kw1">return</span> <span class="br0">(</span>Lang.<span class="me1">isNumber</span><span class="br0">(</span>val<span class="br0">)</span> <span class="sy0">&&</span> val <span class="sy0">&</span>gt<span class="sy0">;=</span> min <span class="sy0">&&</span> val <span class="sy0">&</span>lt<span class="sy0">;=</span> max<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="coMULTI">/* |
|
895 * value attribute change listener. Updates the |
|
896 * value in the rendered input box, whenever the |
|
897 * attribute value changes. |
|
898 */</span> |
|
899 _afterValueChange <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
900 <span class="kw1">this</span>._uiSetValue<span class="br0">(</span>e.<span class="me1">newVal</span><span class="br0">)</span><span class="sy0">;</span> |
|
901 <span class="br0">}</span><span class="sy0">,</span> |
|
902 |
|
903 <span class="coMULTI">/* |
|
904 * Updates the value of the input box to reflect |
|
905 * the value passed in |
|
906 */</span> |
|
907 _uiSetValue <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>val<span class="br0">)</span> <span class="br0">{</span> |
|
908 <span class="kw1">this</span>.<span class="me1">inputNode</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> val<span class="br0">)</span><span class="sy0">;</span> |
|
909 <span class="br0">}</span><span class="sy0">,</span> |
|
910 |
|
911 <span class="coMULTI">/* |
|
912 * value attribute default validator. Verifies that |
|
913 * the value being set lies between the min/max value |
|
914 */</span> |
|
915 _validateValue<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>val<span class="br0">)</span> <span class="br0">{</span> |
|
916 <span class="kw2">var</span> min <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"min"</span><span class="br0">)</span><span class="sy0">,</span> |
|
917 max <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"max"</span><span class="br0">)</span><span class="sy0">;</span> |
|
918 |
|
919 <span class="kw1">return</span> <span class="br0">(</span>Lang.<span class="me1">isNumber</span><span class="br0">(</span>val<span class="br0">)</span> <span class="sy0">&&</span> val <span class="sy0">&</span>gt<span class="sy0">;=</span> min <span class="sy0">&&</span> val <span class="sy0">&</span>lt<span class="sy0">;=</span> max<span class="br0">)</span><span class="sy0">;</span> |
|
920 <span class="br0">}</span></pre></div><textarea id="syntax5-plain">/* |
|
921 * value attribute change listener. Updates the |
|
922 * value in the rendered input box, whenever the |
|
923 * attribute value changes. |
|
924 */ |
|
925 _afterValueChange : function(e) { |
|
926 this._uiSetValue(e.newVal); |
|
927 }, |
|
928 |
|
929 /* |
|
930 * Updates the value of the input box to reflect |
|
931 * the value passed in |
|
932 */ |
|
933 _uiSetValue : function(val) { |
|
934 this.inputNode.set("value", val); |
|
935 }, |
|
936 |
|
937 /* |
|
938 * value attribute default validator. Verifies that |
|
939 * the value being set lies between the min/max value |
|
940 */ |
|
941 _validateValue: function(val) { |
|
942 var min = this.get("min"), |
|
943 max = this.get("max"); |
|
944 |
|
945 return (Lang.isNumber(val) && val >= min && val <= max); |
|
946 }</textarea></div> |
|
947 <p>Since this example focuses on general patterns for widget development, validator/set/get functions are not defined for attributes such as min/max in the interests of keeping the example simple, but could be, in a production ready spinner.</p> |
|
948 |
|
949 <h4>Rendering Support Methods</h4> |
|
950 |
|
951 <p><code>Spinner</code>'s <code>renderUI</code> method hands off creation of the input field and buttons to the following helpers which use markup templates to generate node instances:</p> |
|
952 |
|
953 <div id="syntax6" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * Creates the input field for the spinner and adds it to</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * the widget's content box, if not already in the markup.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li2"><div class="de2">_renderInput <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> contentBox <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"contentBox"</span><span class="br0">)</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> input <span class="sy0">=</span> contentBox.<span class="me1">one</span><span class="br0">(</span><span class="st0">"."</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">)</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> strings <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"strings"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span>input<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> input <span class="sy0">=</span> Node.<span class="me1">create</span><span class="br0">(</span>Spinner.<span class="me1">INPUT_TEMPLATE</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> contentBox.<span class="me1">appendChild</span><span class="br0">(</span>input<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> input.<span class="me1">set</span><span class="br0">(</span><span class="st0">"title"</span><span class="sy0">,</span> strings.<span class="me1">tooltip</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">inputNode</span> <span class="sy0">=</span> input<span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * Creates the button controls for the spinner and add them to</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * the widget's content box, if not already in the markup.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">_renderButtons <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> contentBox <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"contentBox"</span><span class="br0">)</span><span class="sy0">,</span></div></li><li class="li2"><div class="de2"> strings <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"strings"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> inc <span class="sy0">=</span> <span class="kw1">this</span>._createButton<span class="br0">(</span>strings.<span class="me1">increment</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"increment"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> dec <span class="sy0">=</span> <span class="kw1">this</span>._createButton<span class="br0">(</span>strings.<span class="me1">decrement</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"decrement"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>.<span class="me1">incrementNode</span> <span class="sy0">=</span> contentBox.<span class="me1">appendChild</span><span class="br0">(</span>inc<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">decrementNode</span> <span class="sy0">=</span> contentBox.<span class="me1">appendChild</span><span class="br0">(</span>dec<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * Utility method, to create a spinner button</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">_createButton <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>text<span class="sy0">,</span> className<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> btn <span class="sy0">=</span> Y.<span class="me1">Node</span>.<span class="me1">create</span><span class="br0">(</span>Spinner.<span class="me1">BTN_TEMPLATE</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> btn.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> text<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> btn.<span class="me1">set</span><span class="br0">(</span><span class="st0">"title"</span><span class="sy0">,</span> text<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> btn.<span class="me1">addClass</span><span class="br0">(</span>className<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"> <span class="kw1">return</span> btn<span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="br0">}</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="coMULTI">/* |
|
954 * Creates the input field for the spinner and adds it to |
|
955 * the widget's content box, if not already in the markup. |
|
956 */</span> |
|
957 _renderInput <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> |
|
958 <span class="kw2">var</span> contentBox <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"contentBox"</span><span class="br0">)</span><span class="sy0">,</span> |
|
959 input <span class="sy0">=</span> contentBox.<span class="me1">one</span><span class="br0">(</span><span class="st0">"."</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">)</span><span class="sy0">,</span> |
|
960 strings <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"strings"</span><span class="br0">)</span><span class="sy0">;</span> |
|
961 |
|
962 <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span>input<span class="br0">)</span> <span class="br0">{</span> |
|
963 input <span class="sy0">=</span> Node.<span class="me1">create</span><span class="br0">(</span>Spinner.<span class="me1">INPUT_TEMPLATE</span><span class="br0">)</span><span class="sy0">;</span> |
|
964 contentBox.<span class="me1">appendChild</span><span class="br0">(</span>input<span class="br0">)</span><span class="sy0">;</span> |
|
965 <span class="br0">}</span> |
|
966 |
|
967 input.<span class="me1">set</span><span class="br0">(</span><span class="st0">"title"</span><span class="sy0">,</span> strings.<span class="me1">tooltip</span><span class="br0">)</span><span class="sy0">;</span> |
|
968 <span class="kw1">this</span>.<span class="me1">inputNode</span> <span class="sy0">=</span> input<span class="sy0">;</span> |
|
969 <span class="br0">}</span><span class="sy0">,</span> |
|
970 |
|
971 <span class="coMULTI">/* |
|
972 * Creates the button controls for the spinner and add them to |
|
973 * the widget's content box, if not already in the markup. |
|
974 */</span> |
|
975 _renderButtons <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> |
|
976 <span class="kw2">var</span> contentBox <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"contentBox"</span><span class="br0">)</span><span class="sy0">,</span> |
|
977 strings <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"strings"</span><span class="br0">)</span><span class="sy0">;</span> |
|
978 |
|
979 <span class="kw2">var</span> inc <span class="sy0">=</span> <span class="kw1">this</span>._createButton<span class="br0">(</span>strings.<span class="me1">increment</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"increment"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span> |
|
980 <span class="kw2">var</span> dec <span class="sy0">=</span> <span class="kw1">this</span>._createButton<span class="br0">(</span>strings.<span class="me1">decrement</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"decrement"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span> |
|
981 |
|
982 <span class="kw1">this</span>.<span class="me1">incrementNode</span> <span class="sy0">=</span> contentBox.<span class="me1">appendChild</span><span class="br0">(</span>inc<span class="br0">)</span><span class="sy0">;</span> |
|
983 <span class="kw1">this</span>.<span class="me1">decrementNode</span> <span class="sy0">=</span> contentBox.<span class="me1">appendChild</span><span class="br0">(</span>dec<span class="br0">)</span><span class="sy0">;</span> |
|
984 <span class="br0">}</span><span class="sy0">,</span> |
|
985 |
|
986 <span class="coMULTI">/* |
|
987 * Utility method, to create a spinner button |
|
988 */</span> |
|
989 _createButton <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>text<span class="sy0">,</span> className<span class="br0">)</span> <span class="br0">{</span> |
|
990 |
|
991 <span class="kw2">var</span> btn <span class="sy0">=</span> Y.<span class="me1">Node</span>.<span class="me1">create</span><span class="br0">(</span>Spinner.<span class="me1">BTN_TEMPLATE</span><span class="br0">)</span><span class="sy0">;</span> |
|
992 btn.<span class="me1">set</span><span class="br0">(</span><span class="st0">"innerHTML"</span><span class="sy0">,</span> text<span class="br0">)</span><span class="sy0">;</span> |
|
993 btn.<span class="me1">set</span><span class="br0">(</span><span class="st0">"title"</span><span class="sy0">,</span> text<span class="br0">)</span><span class="sy0">;</span> |
|
994 btn.<span class="me1">addClass</span><span class="br0">(</span>className<span class="br0">)</span><span class="sy0">;</span> |
|
995 |
|
996 <span class="kw1">return</span> btn<span class="sy0">;</span> |
|
997 <span class="br0">}</span></pre></div><textarea id="syntax6-plain">/* |
|
998 * Creates the input field for the spinner and adds it to |
|
999 * the widget's content box, if not already in the markup. |
|
1000 */ |
|
1001 _renderInput : function() { |
|
1002 var contentBox = this.get("contentBox"), |
|
1003 input = contentBox.one("." + Spinner.INPUT_CLASS), |
|
1004 strings = this.get("strings"); |
|
1005 |
|
1006 if (!input) { |
|
1007 input = Node.create(Spinner.INPUT_TEMPLATE); |
|
1008 contentBox.appendChild(input); |
|
1009 } |
|
1010 |
|
1011 input.set("title", strings.tooltip); |
|
1012 this.inputNode = input; |
|
1013 }, |
|
1014 |
|
1015 /* |
|
1016 * Creates the button controls for the spinner and add them to |
|
1017 * the widget's content box, if not already in the markup. |
|
1018 */ |
|
1019 _renderButtons : function() { |
|
1020 var contentBox = this.get("contentBox"), |
|
1021 strings = this.get("strings"); |
|
1022 |
|
1023 var inc = this._createButton(strings.increment, this.getClassName("increment")); |
|
1024 var dec = this._createButton(strings.decrement, this.getClassName("decrement")); |
|
1025 |
|
1026 this.incrementNode = contentBox.appendChild(inc); |
|
1027 this.decrementNode = contentBox.appendChild(dec); |
|
1028 }, |
|
1029 |
|
1030 /* |
|
1031 * Utility method, to create a spinner button |
|
1032 */ |
|
1033 _createButton : function(text, className) { |
|
1034 |
|
1035 var btn = Y.Node.create(Spinner.BTN_TEMPLATE); |
|
1036 btn.set("innerHTML", text); |
|
1037 btn.set("title", text); |
|
1038 btn.addClass(className); |
|
1039 |
|
1040 return btn; |
|
1041 }</textarea></div> |
|
1042 <h4>DOM Event Listeners</h4> |
|
1043 |
|
1044 <p>The DOM event listeners attached during <code>bindUI</code> are straightforward event listeners, which receive the event facade for the DOM event, and update the spinner state accordingly.</p> |
|
1045 |
|
1046 <p>A couple of interesting points worth noting: In the <code>"key"</code> listener we set up, we can call <code>e.preventDefault()</code> without having to check the character code, since the <code>"key"</code> event specifier will only invoke the listener |
|
1047 if one of the specified keys is pressed (arrow/page up/down)</p> |
|
1048 |
|
1049 <p>Also, to allow the spinner to update it's value while the mouse button is held down, we setup a timer, which gets cleared out when we receive a mouseup event on the document.</p> |
|
1050 |
|
1051 <div id="syntax7" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * Bounding box Arrow up/down, Page up/down key listener.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> *</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * Increments/Decrement the spinner value, based on the key pressed.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">_onDirectionKey <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> e.<span class="me1">preventDefault</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> ...</div></li><li class="li1"><div class="de1"> <span class="kw1">switch</span> <span class="br0">(</span>e.<span class="me1">charCode</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li2"><div class="de2"> <span class="kw1">case</span> <span class="nu0">38</span><span class="sy0">:</span></div></li><li class="li1"><div class="de1"> newVal <span class="sy0">+=</span> minorStep<span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">break</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">case</span> <span class="nu0">40</span><span class="sy0">:</span></div></li><li class="li1"><div class="de1"> newVal <span class="sy0">-=</span> minorStep<span class="sy0">;</span></div></li><li class="li2"><div class="de2"> <span class="kw1">break</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">case</span> <span class="nu0">33</span><span class="sy0">:</span></div></li><li class="li1"><div class="de1"> newVal <span class="sy0">+=</span> majorStep<span class="sy0">;</span></div></li><li class="li1"><div class="de1"> newVal <span class="sy0">=</span> Math.<span class="me1">min</span><span class="br0">(</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"max"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">break</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> <span class="kw1">case</span> <span class="nu0">34</span><span class="sy0">:</span></div></li><li class="li1"><div class="de1"> newVal <span class="sy0">-=</span> majorStep<span class="sy0">;</span></div></li><li class="li1"><div class="de1"> newVal <span class="sy0">=</span> Math.<span class="me1">max</span><span class="br0">(</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"min"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">break</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span>newVal <span class="sy0">!==</span> currVal<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> newVal<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * Bounding box mouse down handler. Will determine if the mouse down</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * is on one of the spinner buttons, and increment/decrement the value</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * accordingly.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * </span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * The method also sets up a timer, to support the user holding the mouse</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * down on the spinner buttons. The timer is cleared when a mouse up event</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * is detected.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li2"><div class="de2">_onMouseDown <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw2">var</span> node <span class="sy0">=</span> e.<span class="me1">target</span></div></li><li class="li1"><div class="de1"> ...</div></li><li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span>node.<span class="me1">hasClass</span><span class="br0">(</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"increment"</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> currVal <span class="sy0">+</span> minorStep<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"> ...</div></li><li class="li1"><div class="de1"> <span class="br0">}</span> <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">(</span>node.<span class="me1">hasClass</span><span class="br0">(</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"decrement"</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> currVal <span class="sy0">-</span> minorStep<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> ...</div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span>handled<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>._setMouseDownTimers<span class="br0">(</span>dir<span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * Document mouse up handler. Clears the timers supporting</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> * the "mouse held down" behavior.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li2"><div class="de2">_onDocMouseUp <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">this</span>._clearMouseDownTimers<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI"> * Simple change handler, to make sure user does not input an invalid value</span></div></li><li class="li1"><div class="de1"><span class="coMULTI"> */</span></div></li><li class="li1"><div class="de1">_onInputChange <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><span class="kw1">this</span>._validateValue<span class="br0">(</span><span class="kw1">this</span>.<span class="me1">inputNode</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"value"</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="co1">// If the entered value is not valid, re-display the stored value</span></div></li><li class="li2"><div class="de2"> <span class="kw1">this</span>.<span class="me1">syncUI</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="br0">}</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="coMULTI">/* |
|
1052 * Bounding box Arrow up/down, Page up/down key listener. |
|
1053 * |
|
1054 * Increments/Decrement the spinner value, based on the key pressed. |
|
1055 */</span> |
|
1056 _onDirectionKey <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
1057 e.<span class="me1">preventDefault</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
1058 ... |
|
1059 <span class="kw1">switch</span> <span class="br0">(</span>e.<span class="me1">charCode</span><span class="br0">)</span> <span class="br0">{</span> |
|
1060 <span class="kw1">case</span> <span class="nu0">38</span><span class="sy0">:</span> |
|
1061 newVal <span class="sy0">+=</span> minorStep<span class="sy0">;</span> |
|
1062 <span class="kw1">break</span><span class="sy0">;</span> |
|
1063 <span class="kw1">case</span> <span class="nu0">40</span><span class="sy0">:</span> |
|
1064 newVal <span class="sy0">-=</span> minorStep<span class="sy0">;</span> |
|
1065 <span class="kw1">break</span><span class="sy0">;</span> |
|
1066 <span class="kw1">case</span> <span class="nu0">33</span><span class="sy0">:</span> |
|
1067 newVal <span class="sy0">+=</span> majorStep<span class="sy0">;</span> |
|
1068 newVal <span class="sy0">=</span> Math.<span class="me1">min</span><span class="br0">(</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"max"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span> |
|
1069 <span class="kw1">break</span><span class="sy0">;</span> |
|
1070 <span class="kw1">case</span> <span class="nu0">34</span><span class="sy0">:</span> |
|
1071 newVal <span class="sy0">-=</span> majorStep<span class="sy0">;</span> |
|
1072 newVal <span class="sy0">=</span> Math.<span class="me1">max</span><span class="br0">(</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"min"</span><span class="br0">)</span><span class="br0">)</span><span class="sy0">;</span> |
|
1073 <span class="kw1">break</span><span class="sy0">;</span> |
|
1074 <span class="br0">}</span> |
|
1075 |
|
1076 <span class="kw1">if</span> <span class="br0">(</span>newVal <span class="sy0">!==</span> currVal<span class="br0">)</span> <span class="br0">{</span> |
|
1077 <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> newVal<span class="br0">)</span><span class="sy0">;</span> |
|
1078 <span class="br0">}</span> |
|
1079 <span class="br0">}</span><span class="sy0">,</span> |
|
1080 |
|
1081 <span class="coMULTI">/* |
|
1082 * Bounding box mouse down handler. Will determine if the mouse down |
|
1083 * is on one of the spinner buttons, and increment/decrement the value |
|
1084 * accordingly. |
|
1085 * |
|
1086 * The method also sets up a timer, to support the user holding the mouse |
|
1087 * down on the spinner buttons. The timer is cleared when a mouse up event |
|
1088 * is detected. |
|
1089 */</span> |
|
1090 _onMouseDown <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
1091 <span class="kw2">var</span> node <span class="sy0">=</span> e.<span class="me1">target</span> |
|
1092 ... |
|
1093 <span class="kw1">if</span> <span class="br0">(</span>node.<span class="me1">hasClass</span><span class="br0">(</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"increment"</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span> |
|
1094 <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> currVal <span class="sy0">+</span> minorStep<span class="br0">)</span><span class="sy0">;</span> |
|
1095 ... |
|
1096 <span class="br0">}</span> <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">(</span>node.<span class="me1">hasClass</span><span class="br0">(</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"decrement"</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span> |
|
1097 <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">(</span><span class="st0">"value"</span><span class="sy0">,</span> currVal <span class="sy0">-</span> minorStep<span class="br0">)</span><span class="sy0">;</span> |
|
1098 ... |
|
1099 <span class="br0">}</span> |
|
1100 |
|
1101 <span class="kw1">if</span> <span class="br0">(</span>handled<span class="br0">)</span> <span class="br0">{</span> |
|
1102 <span class="kw1">this</span>._setMouseDownTimers<span class="br0">(</span>dir<span class="br0">)</span><span class="sy0">;</span> |
|
1103 <span class="br0">}</span> |
|
1104 <span class="br0">}</span><span class="sy0">,</span> |
|
1105 |
|
1106 <span class="coMULTI">/* |
|
1107 * Document mouse up handler. Clears the timers supporting |
|
1108 * the "mouse held down" behavior. |
|
1109 */</span> |
|
1110 _onDocMouseUp <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
1111 <span class="kw1">this</span>._clearMouseDownTimers<span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
1112 <span class="br0">}</span><span class="sy0">,</span> |
|
1113 |
|
1114 <span class="coMULTI">/* |
|
1115 * Simple change handler, to make sure user does not input an invalid value |
|
1116 */</span> |
|
1117 _onInputChange <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">(</span>e<span class="br0">)</span> <span class="br0">{</span> |
|
1118 <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">!</span><span class="kw1">this</span>._validateValue<span class="br0">(</span><span class="kw1">this</span>.<span class="me1">inputNode</span>.<span class="me1">get</span><span class="br0">(</span><span class="st0">"value"</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span> |
|
1119 <span class="co1">// If the entered value is not valid, re-display the stored value</span> |
|
1120 <span class="kw1">this</span>.<span class="me1">syncUI</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
1121 <span class="br0">}</span> |
|
1122 <span class="br0">}</span></pre></div><textarea id="syntax7-plain">/* |
|
1123 * Bounding box Arrow up/down, Page up/down key listener. |
|
1124 * |
|
1125 * Increments/Decrement the spinner value, based on the key pressed. |
|
1126 */ |
|
1127 _onDirectionKey : function(e) { |
|
1128 e.preventDefault(); |
|
1129 ... |
|
1130 switch (e.charCode) { |
|
1131 case 38: |
|
1132 newVal += minorStep; |
|
1133 break; |
|
1134 case 40: |
|
1135 newVal -= minorStep; |
|
1136 break; |
|
1137 case 33: |
|
1138 newVal += majorStep; |
|
1139 newVal = Math.min(newVal, this.get("max")); |
|
1140 break; |
|
1141 case 34: |
|
1142 newVal -= majorStep; |
|
1143 newVal = Math.max(newVal, this.get("min")); |
|
1144 break; |
|
1145 } |
|
1146 |
|
1147 if (newVal !== currVal) { |
|
1148 this.set("value", newVal); |
|
1149 } |
|
1150 }, |
|
1151 |
|
1152 /* |
|
1153 * Bounding box mouse down handler. Will determine if the mouse down |
|
1154 * is on one of the spinner buttons, and increment/decrement the value |
|
1155 * accordingly. |
|
1156 * |
|
1157 * The method also sets up a timer, to support the user holding the mouse |
|
1158 * down on the spinner buttons. The timer is cleared when a mouse up event |
|
1159 * is detected. |
|
1160 */ |
|
1161 _onMouseDown : function(e) { |
|
1162 var node = e.target |
|
1163 ... |
|
1164 if (node.hasClass(this.getClassName("increment"))) { |
|
1165 this.set("value", currVal + minorStep); |
|
1166 ... |
|
1167 } else if (node.hasClass(this.getClassName("decrement"))) { |
|
1168 this.set("value", currVal - minorStep); |
|
1169 ... |
|
1170 } |
|
1171 |
|
1172 if (handled) { |
|
1173 this._setMouseDownTimers(dir); |
|
1174 } |
|
1175 }, |
|
1176 |
|
1177 /* |
|
1178 * Document mouse up handler. Clears the timers supporting |
|
1179 * the "mouse held down" behavior. |
|
1180 */ |
|
1181 _onDocMouseUp : function(e) { |
|
1182 this._clearMouseDownTimers(); |
|
1183 }, |
|
1184 |
|
1185 /* |
|
1186 * Simple change handler, to make sure user does not input an invalid value |
|
1187 */ |
|
1188 _onInputChange : function(e) { |
|
1189 if (!this._validateValue(this.inputNode.get("value"))) { |
|
1190 // If the entered value is not valid, re-display the stored value |
|
1191 this.syncUI(); |
|
1192 } |
|
1193 }</textarea></div> |
|
1194 <h4>ClassName Support Methods</h4> |
|
1195 |
|
1196 <p>A key part of developing widgets which work with the DOM, is defining class names which it will use to mark the nodes it renders. These class names could be used to mark a node for later retrieval/lookup, for CSS application (both functional as well as cosmetic) or to indicate the current state of the widget.</p> |
|
1197 |
|
1198 <p>The widget infrastructure uses the <code>ClassNameManager</code> utility, to generate consistently named classes to apply to the nodes it adds to the page:</p> |
|
1199 |
|
1200 <div id="syntax8" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1">Y.<span class="me1">ClassNameManager</span>.<span class="me1">getClassName</span><span class="br0">(</span>Spinner.<span class="kw3">NAME</span><span class="sy0">,</span> <span class="st0">"value"</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">...</div></li><li class="li1"><div class="de1"><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"increment"</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;">Y.<span class="me1">ClassNameManager</span>.<span class="me1">getClassName</span><span class="br0">(</span>Spinner.<span class="kw3">NAME</span><span class="sy0">,</span> <span class="st0">"value"</span><span class="br0">)</span><span class="sy0">;</span> |
|
1201 ... |
|
1202 <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">(</span><span class="st0">"increment"</span><span class="br0">)</span><span class="sy0">;</span></pre></div><textarea id="syntax8-plain">Y.ClassNameManager.getClassName(Spinner.NAME, "value"); |
|
1203 ... |
|
1204 this.getClassName("increment");</textarea></div> |
|
1205 <p> |
|
1206 Class names generated by the Widget's <code>getClassName</code> prototype method use the NAME field of the widget, to generate a prefixed classname through <code>ClassNameManager</code> - e.g. for spinner the <code>this.getClassName("increment")</code> above will generate the class name <code>yui-spinner-increment</code> ("yui" being the system level prefix, "spinner" being the widget name). |
|
1207 When you need to generate standard class names in static code (where you don't have a reference to <code>this.getClassName()</code>), you can use the ClassNameManager directly, as shown in line 1 above, to achieve the same results. |
|
1208 </p> |
|
1209 |
|
1210 <h4>CSS Considerations</h4> |
|
1211 |
|
1212 <p>Since widget uses the <code>getClassName</code> method to generate state related class names and to mark the bounding box/content box of the widget (e.g. "yui-[widgetname]-content", "yui-[widgetname]-hidden", "yui-[widgetname]-disabled"), we need to provide the default CSS handling for states we're interested in handling for the new Spinner widget. The "yui-[widgetname]-hidden" class is probably one state class, which all widgets will provide implementations for.</p> |
|
1213 |
|
1214 <div id="syntax9" class="yui-syntax-highlight"><div class="numbers"><pre class="css" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="coMULTI">/* Controlling show/hide state using display (since this control is inline-block) */</span></div></li><li class="li1"><div class="de1"><span class="re1">.yui-spinner-hidden</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">display</span><span class="sy0">:</span><span class="kw2">none</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li><li class="li2"><div class="de2"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/* Bounding Box - Set the bounding box to be "inline block" for spinner */</span></div></li><li class="li1"><div class="de1"><span class="re1">.yui-spinner</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">display</span><span class="re2">:-moz-inline-</span>stack<span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="kw1">display</span><span class="re2">:inline-</span>block<span class="sy0">;</span></div></li><li class="li2"><div class="de2"> zoom<span class="sy0">:</span><span class="nu0">1</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"> <span class="sy0">*</span><span class="kw1">display</span><span class="sy0">:</span><span class="kw2">inline</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/* Content Box - Start adding visual treatment for the spinner */</span></div></li><li class="li2"><div class="de2"><span class="re1">.yui-spinner-content</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> <span class="kw1">padding</span><span class="sy0">:</span><span class="re3">1px</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/* Input Text Box, generated through getClassName("value") */</span></div></li><li class="li2"><div class="de2"><span class="re1">.yui-spinner-value</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> ...</div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li><li class="li1"><div class="de1"> </div></li><li class="li1"><div class="de1"><span class="coMULTI">/* Button controls, generated through getClassName("increment") */</span></div></li><li class="li2"><div class="de2"><span class="re1">.yui-spinner-increment</span><span class="sy0">,</span> <span class="re1">.yui-spinner-decrement</span> <span class="br0">{</span></div></li><li class="li1"><div class="de1"> ...</div></li><li class="li1"><div class="de1"><span class="br0">}</span></div></li></ol></pre></div><div class="nonumbers"><pre class="css" style="font-family:monospace;"><span class="coMULTI">/* Controlling show/hide state using display (since this control is inline-block) */</span> |
|
1215 <span class="re1">.yui-spinner-hidden</span> <span class="br0">{</span> |
|
1216 <span class="kw1">display</span><span class="sy0">:</span><span class="kw2">none</span><span class="sy0">;</span> |
|
1217 <span class="br0">}</span> |
|
1218 |
|
1219 <span class="coMULTI">/* Bounding Box - Set the bounding box to be "inline block" for spinner */</span> |
|
1220 <span class="re1">.yui-spinner</span> <span class="br0">{</span> |
|
1221 <span class="kw1">display</span><span class="re2">:-moz-inline-</span>stack<span class="sy0">;</span> |
|
1222 <span class="kw1">display</span><span class="re2">:inline-</span>block<span class="sy0">;</span> |
|
1223 zoom<span class="sy0">:</span><span class="nu0">1</span><span class="sy0">;</span> |
|
1224 <span class="sy0">*</span><span class="kw1">display</span><span class="sy0">:</span><span class="kw2">inline</span><span class="sy0">;</span> |
|
1225 <span class="br0">}</span> |
|
1226 |
|
1227 <span class="coMULTI">/* Content Box - Start adding visual treatment for the spinner */</span> |
|
1228 <span class="re1">.yui-spinner-content</span> <span class="br0">{</span> |
|
1229 <span class="kw1">padding</span><span class="sy0">:</span><span class="re3">1px</span><span class="sy0">;</span> |
|
1230 <span class="br0">}</span> |
|
1231 |
|
1232 <span class="coMULTI">/* Input Text Box, generated through getClassName("value") */</span> |
|
1233 <span class="re1">.yui-spinner-value</span> <span class="br0">{</span> |
|
1234 ... |
|
1235 <span class="br0">}</span> |
|
1236 |
|
1237 <span class="coMULTI">/* Button controls, generated through getClassName("increment") */</span> |
|
1238 <span class="re1">.yui-spinner-increment</span><span class="sy0">,</span> <span class="re1">.yui-spinner-decrement</span> <span class="br0">{</span> |
|
1239 ... |
|
1240 <span class="br0">}</span></pre></div><textarea id="syntax9-plain">/* Controlling show/hide state using display (since this control is inline-block) */ |
|
1241 .yui-spinner-hidden { |
|
1242 display:none; |
|
1243 } |
|
1244 |
|
1245 /* Bounding Box - Set the bounding box to be "inline block" for spinner */ |
|
1246 .yui-spinner { |
|
1247 display:-moz-inline-stack; |
|
1248 display:inline-block; |
|
1249 zoom:1; |
|
1250 *display:inline; |
|
1251 } |
|
1252 |
|
1253 /* Content Box - Start adding visual treatment for the spinner */ |
|
1254 .yui-spinner-content { |
|
1255 padding:1px; |
|
1256 } |
|
1257 |
|
1258 /* Input Text Box, generated through getClassName("value") */ |
|
1259 .yui-spinner-value { |
|
1260 ... |
|
1261 } |
|
1262 |
|
1263 /* Button controls, generated through getClassName("increment") */ |
|
1264 .yui-spinner-increment, .yui-spinner-decrement { |
|
1265 ... |
|
1266 }</textarea></div> |
|
1267 <h4>Using The Spinner Widget</h4> |
|
1268 |
|
1269 <p>For the example, we have an input field already on the page, which we'd like to enhance to create a Spinner instance:</p> |
|
1270 |
|
1271 <div id="syntax10" class="yui-syntax-highlight"><div class="numbers"><pre class="html4strict" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="sc2"><<span class="kw2">div</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">"numberField"</span>></span></div></li><li class="li1"><div class="de1"> <span class="sc2"><<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">"text"</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">"yui-spinner-value"</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">"20"</span> <span class="sy0">/</span>></span></div></li><li class="li1"><div class="de1"><span class="sc2"><<span class="sy0">/</span><span class="kw2">div</span>></span></div></li></ol></pre></div><div class="nonumbers"><pre class="html4strict" style="font-family:monospace;"><span class="sc2"><<span class="kw2">div</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">"numberField"</span>></span> |
|
1272 <span class="sc2"><<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">"text"</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">"yui-spinner-value"</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">"20"</span> <span class="sy0">/</span>></span> |
|
1273 <span class="sc2"><<span class="sy0">/</span><span class="kw2">div</span>></span></pre></div><textarea id="syntax10-plain"><div id="numberField"> |
|
1274 <input type="text" class="yui-spinner-value" value="20" /> |
|
1275 </div></textarea></div> |
|
1276 <p>We provide the constructor for the Spinner with the <code>contentBox</code> which contains the input field with our initial value. The <code>HTML_PARSER</code> code we saw earlier, will extract the value from the input field, and use it as the initial value for the Spinner instance:</p> |
|
1277 |
|
1278 <div id="syntax11" class="yui-syntax-highlight"><div class="numbers"><pre class="javascript" style="font-family:monospace;"><ol><li class="li1"><div class="de1"><span class="co1">// Create a new Spinner instance, drawing it's </span></div></li><li class="li1"><div class="de1"><span class="co1">// starting value from an input field already on the </span></div></li><li class="li1"><div class="de1"><span class="co1">// page (contained in the #numberField content box)</span></div></li><li class="li1"><div class="de1"><span class="kw2">var</span> spinner <span class="sy0">=</span> <span class="kw2">new</span> Spinner<span class="br0">(</span><span class="br0">{</span></div></li><li class="li2"><div class="de2"> contentBox<span class="sy0">:</span> <span class="st0">"#numberField"</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> max<span class="sy0">:</span><span class="nu0">100</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1"> min<span class="sy0">:</span><span class="nu0">0</span></div></li><li class="li1"><div class="de1"><span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">spinner.<span class="me1">render</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">spinner.<span class="kw3">focus</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="javascript" style="font-family:monospace;"><span class="co1">// Create a new Spinner instance, drawing it's </span> |
|
1279 <span class="co1">// starting value from an input field already on the </span> |
|
1280 <span class="co1">// page (contained in the #numberField content box)</span> |
|
1281 <span class="kw2">var</span> spinner <span class="sy0">=</span> <span class="kw2">new</span> Spinner<span class="br0">(</span><span class="br0">{</span> |
|
1282 contentBox<span class="sy0">:</span> <span class="st0">"#numberField"</span><span class="sy0">,</span> |
|
1283 max<span class="sy0">:</span><span class="nu0">100</span><span class="sy0">,</span> |
|
1284 min<span class="sy0">:</span><span class="nu0">0</span> |
|
1285 <span class="br0">}</span><span class="br0">)</span><span class="sy0">;</span> |
|
1286 spinner.<span class="me1">render</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span> |
|
1287 spinner.<span class="kw3">focus</span><span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></pre></div><textarea id="syntax11-plain">// Create a new Spinner instance, drawing it's |
|
1288 // starting value from an input field already on the |
|
1289 // page (contained in the #numberField content box) |
|
1290 var spinner = new Spinner({ |
|
1291 contentBox: "#numberField", |
|
1292 max:100, |
|
1293 min:0 |
|
1294 }); |
|
1295 spinner.render(); |
|
1296 spinner.focus();</textarea></div> </div> |
|
1297 <div class="yui-u sidebar"> |
|
1298 |
|
1299 |
|
1300 <div id="examples" class="mod box4"> |
|
1301 <div class="hd"> |
|
1302 <h4> |
|
1303 Widget Examples:</h4> |
|
1304 </div> |
|
1305 <div class="bd"> |
|
1306 <ul> |
|
1307 <li class='selected'><a href='../widget/widget-extend.html'>Extending the base widget class</a></li><li><a href='../widget/widget-build.html'>Creating custom widget classes</a></li><li><a href='../widget/widget-tooltip.html'>Creating a simple Tooltip widget</a></li> </ul> |
|
1308 </div> |
|
1309 </div> |
|
1310 |
|
1311 <div class="mod box4"> |
|
1312 <div class="hd"> |
|
1313 <h4>More Widget Resources:</h4> |
|
1314 </div> |
|
1315 <div class="bd"> |
|
1316 <ul> |
|
1317 <!-- <li><a href="http://developer.yahoo.com/yui/widget/">User's Guide</a> (external)</li> --> |
|
1318 <li><a href="../../api/module_widget.html">API Documentation</a></li></ul> |
|
1319 </div> |
|
1320 </div> |
|
1321 </div> |
|
1322 </div> |
|
1323 |
|
1324 </div> |
|
1325 </div> |
|
1326 |
|
1327 |
|
1328 <div class="yui-b toc3" id="tocWrapper"> |
|
1329 <!-- TABLE OF CONTENTS --> |
|
1330 <div id="toc"> |
|
1331 |
|
1332 <ul> |
|
1333 <li class="sect first">YUI 3 Resources</li><li class="item"><a title="YUI 3 -- Yahoo! User Interface (YUI) Library" href="http://developer.yahoo.com/yui/3/">YUI 3 Web Site</a></li><li class="item"><a title="Examples of every YUI utility and control in action" href="../../examples/">YUI 3 Examples</a></li><li class="item"><a title="Instantly searchable API documentation for the entire YUI library." href="../../api/">YUI 3 API Docs</a></li><li class="item"><a title="YUI 3 Dependency Configurator -- configure your custom YUI implementation" href="http://developer.yahoo.com/yui/3/configurator">YUI 3 Dependency Configurator</a></li><li class="item"><a title="The YUI 3 Forum on YUILibrary.com" href="http://yuilibrary.com/forum/viewforum.php?f=15">YUI 3 Forums (external)</a></li><li class="item"><a title="Found a bug or a missing feature? Let us know on YUILibrary.com." href="http://developer.yahoo.com/yui/articles/reportingbugs/">Bug Reports/Feature Requests</a></li><li class="item"><a title="YUI is free and open, offered under a BSD license." href="http://developer.yahoo.com/yui/license.html">YUI License</a></li><li class="item"><a title="Download and fork the YUI project on GitHub" href="http://github.com/yui">YUI on Github</a></li><li class="item"><a title="The Yahoo! User Interface Blog" href="http://yuiblog.com">YUI Blog (external)</a></li><li class="sect">YUI 3 Core - Examples</li><li class="item"><a title="YUI Global Object - Functional Examples" href="../../examples/yui/index.html">YUI Global Object</a></li><li class="item"><a title="Event - Functional Examples" href="../../examples/event/index.html">Event</a></li><li class="item"><a title="Node - Functional Examples" href="../../examples/node/index.html">Node</a></li><li class="sect">YUI 3 Component Infrastructure - Examples</li><li class="item"><a title="Attribute - Functional Examples" href="../../examples/attribute/index.html">Attribute</a></li><li class="item"><a title="Plugin - Functional Examples" href="../../examples/plugin/index.html">Plugin <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="selected "><a title="Widget - Functional Examples" href="../../examples/widget/index.html">Widget <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="sect">YUI 3 Utilities - Examples</li><li class="item"><a title="Animation - Functional Examples" href="../../examples/anim/index.html">Animation</a></li><li class="item"><a title="AsyncQueue - Functional Examples" href="../../examples/async-queue/index.html">AsyncQueue</a></li><li class="item"><a title="Browser History - Functional Examples" href="../../examples/history/index.html">Browser History</a></li><li class="item"><a title="Cache - Functional Examples" href="../../examples/cache/index.html">Cache</a></li><li class="item"><a title="Cookie - Functional Examples" href="../../examples/cookie/index.html">Cookie</a></li><li class="item"><a title="DataSchema - Functional Examples" href="../../examples/dataschema/index.html">DataSchema <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="DataSource - Functional Examples" href="../../examples/datasource/index.html">DataSource <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="DataType - Functional Examples" href="../../examples/datatype/index.html">DataType <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Drag & Drop - Functional Examples" href="../../examples/dd/index.html">Drag & Drop</a></li><li class="item"><a title="Get - Functional Examples" href="../../examples/get/index.html">Get</a></li><li class="item"><a title="ImageLoader - Functional Examples" href="../../examples/imageloader/index.html">ImageLoader</a></li><li class="item"><a title="IO - Functional Examples" href="../../examples/io/index.html">IO</a></li><li class="item"><a title="JSON (JavaScript Object Notation) - Functional Examples" href="../../examples/json/index.html">JSON</a></li><li class="item"><a title="Stylesheet - Functional Examples" href="../../examples/stylesheet/index.html">Stylesheet</a></li><li class="sect">YUI 3 Widgets - Examples</li><li class="item"><a title="Overlay - Functional Examples" href="../../examples/overlay/index.html">Overlay <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Slider - Functional Examples" href="../../examples/slider/index.html">Slider <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="sect">YUI 3 Node Plugins - Examples</li><li class="item"><a title="FocusManager Node Plugin - Functional Examples" href="../../examples/node-focusmanager/index.html">FocusManager Node Plugin <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="MenuNav Node Plugin - Functional Examples" href="../../examples/node-menunav/index.html">MenuNav Node Plugin <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="sect">YUI 3 CSS - Examples</li><li class="item"><a title="YUI CSS Reset - Functional Examples" href="../../examples/cssreset/index.html">CSS Reset</a></li><li class="item"><a title="YUI Fonts - Functional Examples" href="../../examples/cssfonts/index.html">CSS Fonts</a></li><li class="item"><a title="YUI Base - Functional Examples" href="../../examples/cssbase/index.html">CSS Base</a></li><li class="sect">YUI 3 Developer Tools - Examples</li><li class="item"><a title="Console - Functional Examples" href="../../examples/console/index.html">Console <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Console Filters Plugin- Functional Examples" href="../../examples/console-filters/index.html">Plugin.ConsoleFilters <img src='http://l.yimg.com/a/i/not/beta_1.gif'></a></li><li class="item"><a title="Profiler - Functional Examples" href="../../examples/profiler/index.html">Profiler</a></li><li class="item"><a title="Test - Functional Examples" href="../../examples/test/index.html">Test</a></li><li class="sect">Other Useful YUI 3 Resources</li><li class="item"><a title="Answers to Frequently Asked Questions about the YUI Library" href="http://developer.yahoo.com/yui/articles/faq/">YUI FAQ (external)</a></li><li class="item"><a title="Yahoo!'s philosophy of Graded Browser Support" href="http://developer.yahoo.com/yui/articles/gbs/">Graded Browser Support (external)</a></li><li class="item"><a title="Videos and podcasts from the YUI Team and from the Yahoo! frontend engineering community." href="http://developer.yahoo.com/yui/theater/">YUI Theater (external)</a></li></ul> |
|
1334 </div> |
|
1335 </div> |
|
1336 </div><!--closes bd--> |
|
1337 |
|
1338 <div id="ft"> |
|
1339 <p class="first">Copyright © 2009 Yahoo! Inc. All rights reserved.</p> |
|
1340 <p><a href="http://privacy.yahoo.com/privacy/us/devel/index.html">Privacy Policy</a> - |
|
1341 <a href="http://docs.yahoo.com/info/terms/">Terms of Service</a> - |
|
1342 <a href="http://docs.yahoo.com/info/copyright/copyright.html">Copyright Policy</a> - |
|
1343 <a href="http://careers.yahoo.com/">Job Openings</a></p> |
|
1344 </div> |
|
1345 </div> |
|
1346 <script language="javascript"> |
|
1347 var yuiConfig = {base:"../../build/", timeout: 10000}; |
|
1348 </script> |
|
1349 <script src="../../assets/syntax.js"></script> |
|
1350 <script src="../../assets/dpSyntaxHighlighter.js"></script> |
|
1351 <script language="javascript"> |
|
1352 dp.SyntaxHighlighter.HighlightAll('code'); |
|
1353 </script> |
|
1354 </body> |
|
1355 </html> |