src/cm/media/js/lib/yui/yui3.0.0/examples/widget/widget-extend.html
changeset 0 40c8f766c9b8
equal deleted inserted replaced
-1:000000000000 0:40c8f766c9b8
       
     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 &amp; 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">&#40;</span>config<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="kw1">this</span><span class="sy0">,</span> arguments<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/* </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* Required NAME static field, to identify the Widget class and </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* 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">&nbsp;* class name in camel case). </span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">Spinner.<span class="kw3">NAME</span> <span class="sy0">=</span> <span class="st0">&quot;spinner&quot;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* The attribute configuration for the Spinner widget. Attributes can be</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* defined with default values, get/set functions and validator functions</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* as with any other class extending Base.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">Spinner.<span class="me1">ATTRS</span> <span class="sy0">=</span> <span class="br0">&#123;</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">&#123;</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">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#123;</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">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#123;</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">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">            <span class="kw1">return</span> <span class="kw1">this</span>._validateValue<span class="br0">&#40;</span>val<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">        <span class="br0">&#125;</span></div></li><li class="li2"><div class="de2">    <span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#123;</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">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#123;</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">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#123;</span></div></li><li class="li1"><div class="de1">        value<span class="sy0">:</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">            tooltip<span class="sy0">:</span> <span class="st0">&quot;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.&quot;</span><span class="sy0">,</span></div></li><li class="li2"><div class="de2">            increment<span class="sy0">:</span> <span class="st0">&quot;Increment&quot;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">            decrement<span class="sy0">:</span> <span class="st0">&quot;Decrement&quot;</span></div></li><li class="li1"><div class="de1">        <span class="br0">&#125;</span></div></li><li class="li1"><div class="de1">    <span class="br0">&#125;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1">Y.<span class="me1">extend</span><span class="br0">&#40;</span>Spinner<span class="sy0">,</span> Widget<span class="sy0">,</span> <span class="br0">&#123;</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">&#125;</span><span class="br0">&#41;</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">&#40;</span>config<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   540     Spinner.<span class="me1">superclass</span>.<span class="me1">constructor</span>.<span class="me1">apply</span><span class="br0">&#40;</span><span class="kw1">this</span><span class="sy0">,</span> arguments<span class="br0">&#41;</span><span class="sy0">;</span>
       
   541 <span class="br0">&#125;</span>
       
   542 &nbsp;
       
   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">&quot;spinner&quot;</span><span class="sy0">;</span>
       
   549 &nbsp;
       
   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">&#123;</span>
       
   556     <span class="co1">// The minimum value for the spinner.</span>
       
   557     min <span class="sy0">:</span> <span class="br0">&#123;</span>
       
   558         value<span class="sy0">:</span><span class="nu0">0</span>
       
   559     <span class="br0">&#125;</span><span class="sy0">,</span>
       
   560 &nbsp;
       
   561     <span class="co1">// The maximum value for the spinner.</span>
       
   562     max <span class="sy0">:</span> <span class="br0">&#123;</span>
       
   563         value<span class="sy0">:</span><span class="nu0">100</span>
       
   564     <span class="br0">&#125;</span><span class="sy0">,</span>
       
   565 &nbsp;
       
   566     <span class="co1">// The current value of the spinner.</span>
       
   567     value <span class="sy0">:</span> <span class="br0">&#123;</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">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   570             <span class="kw1">return</span> <span class="kw1">this</span>._validateValue<span class="br0">&#40;</span>val<span class="br0">&#41;</span><span class="sy0">;</span>
       
   571         <span class="br0">&#125;</span>
       
   572     <span class="br0">&#125;</span><span class="sy0">,</span>
       
   573 &nbsp;
       
   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">&#123;</span>
       
   577         value<span class="sy0">:</span><span class="nu0">1</span>
       
   578     <span class="br0">&#125;</span><span class="sy0">,</span>
       
   579 &nbsp;
       
   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">&#123;</span>
       
   582         value<span class="sy0">:</span><span class="nu0">10</span>
       
   583     <span class="br0">&#125;</span><span class="sy0">,</span>
       
   584 &nbsp;
       
   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">&#123;</span>
       
   589         value<span class="sy0">:</span> <span class="br0">&#123;</span>
       
   590             tooltip<span class="sy0">:</span> <span class="st0">&quot;Press the arrow up/down keys for minor increments, <span class="es0">\ </span>
       
   591                       page up/down for major increments.&quot;</span><span class="sy0">,</span>
       
   592             increment<span class="sy0">:</span> <span class="st0">&quot;Increment&quot;</span><span class="sy0">,</span>
       
   593             decrement<span class="sy0">:</span> <span class="st0">&quot;Decrement&quot;</span>
       
   594         <span class="br0">&#125;</span>
       
   595     <span class="br0">&#125;</span>
       
   596 <span class="br0">&#125;</span><span class="sy0">;</span>
       
   597 &nbsp;
       
   598 Y.<span class="me1">extend</span><span class="br0">&#40;</span>Spinner<span class="sy0">,</span> Widget<span class="sy0">,</span> <span class="br0">&#123;</span>
       
   599     <span class="co1">// Methods/properties to add to the prototype of the new class</span>
       
   600     ...
       
   601 <span class="br0">&#125;</span><span class="br0">&#41;</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">&nbsp;* 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">&nbsp;* the configuration for the spinner instance from markup already on the page.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* 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">&nbsp;* finds the appropriate input element on the page.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">Spinner.<span class="me1">HTML_PARSER</span> <span class="sy0">=</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    value<span class="sy0">:</span> <span class="kw2">function</span> <span class="br0">&#40;</span>contentBox<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;.&quot;</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">        <span class="kw1">return</span> <span class="br0">&#40;</span>node<span class="br0">&#41;</span> <span class="sy0">?</span> parseInt<span class="br0">&#40;</span>node.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</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">&#125;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</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">&#123;</span>
       
   689     value<span class="sy0">:</span> <span class="kw2">function</span> <span class="br0">&#40;</span>contentBox<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   690         <span class="kw2">var</span> node <span class="sy0">=</span> contentBox.<span class="me1">one</span><span class="br0">&#40;</span><span class="st0">&quot;.&quot;</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   691         <span class="kw1">return</span> <span class="br0">&#40;</span>node<span class="br0">&#41;</span> <span class="sy0">?</span> parseInt<span class="br0">&#40;</span>node.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="kw2">null</span><span class="sy0">;</span>
       
   692     <span class="br0">&#125;</span>
       
   693 <span class="br0">&#125;</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">&nbsp;* initializer is part of the lifecycle introduced by </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* the Widget class. It is invoked during construction,</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* and can be used to setup instance specific state.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* The Spinner class does not need to perform anything</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* specific in this method, but it is left in as an example.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">initializer<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>config<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* destructor is part of the lifecycle introduced by </span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* the Widget class. It is invoked during destruction,</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* and can be used to cleanup instance specific state.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* The spinner cleans up any node references it's holding</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* onto. The Widget classes destructor will purge the </span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* widget's bounding box of event listeners, so spinner </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* only needs to clean up listeners it attaches outside of </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* the bounding box.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">destructor <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li2"><div class="de2">    <span class="kw1">this</span>._documentMouseUpHandle.<span class="me1">detach</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#125;</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">&#40;</span>config<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   723     <span class="co1">// Not doing anything special during initialization</span>
       
   724 <span class="br0">&#125;</span><span class="sy0">,</span>
       
   725 &nbsp;
       
   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">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   738     <span class="kw1">this</span>._documentMouseUpHandle.<span class="me1">detach</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   739 &nbsp;
       
   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">&#125;</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">&nbsp;* For spinner the method adds the input (if it's not already </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* present in the markup), and creates the increment/decrement buttons</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li2"><div class="de2">renderUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    <span class="kw1">this</span>._renderInput<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    <span class="kw1">this</span>._renderButtons<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li2"><div class="de2"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* For spinner, the method:</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* - Sets up the attribute change listener for the &quot;value&quot; attribute</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* - Binds key listeners for the arrow/page keys</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* - Binds mouseup/down listeners on the boundingBox, document respectively.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* - Binds a simple change listener on the input box.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">bindUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li2"><div class="de2">    <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">&#40;</span><span class="st0">&quot;valueChange&quot;</span><span class="sy0">,</span> <span class="kw1">this</span>._afterValueChange<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#40;</span><span class="st0">&quot;boundingBox&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#40;</span><span class="sy0">!</span>Y.<span class="me1">UA</span>.<span class="me1">opera</span><span class="br0">&#41;</span> <span class="sy0">?</span> <span class="st0">&quot;down:&quot;</span> <span class="sy0">:</span> <span class="st0">&quot;press:&quot;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    keyEventSpec <span class="sy0">+=</span> <span class="st0">&quot;38, 40, 33, 34&quot;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li2"><div class="de2">    Y.<span class="me1">on</span><span class="br0">&#40;</span><span class="st0">&quot;change&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onInputChange<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">inputNode</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    Y.<span class="me1">on</span><span class="br0">&#40;</span><span class="st0">&quot;key&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onDirectionKey<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> boundingBox<span class="sy0">,</span> keyEventSpec<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    Y.<span class="me1">on</span><span class="br0">&#40;</span><span class="st0">&quot;mousedown&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onMouseDown<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> boundingBox<span class="br0">&#41;</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">&#40;</span><span class="st0">&quot;mouseup&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onDocMouseUp<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> </div></li><li class="li1"><div class="de1">                boundingBox.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;ownerDocument&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* For spinner, the method sets the value of the input field,</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* to match the current state of the value attribute.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">syncUI <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    <span class="kw1">this</span>._uiSetValue<span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</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">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   792     <span class="kw1">this</span>._renderInput<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   793     <span class="kw1">this</span>._renderButtons<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   794 <span class="br0">&#125;</span><span class="sy0">,</span>
       
   795 &nbsp;
       
   796 <span class="coMULTI">/*
       
   797  * For spinner, the method:
       
   798  *
       
   799  * - Sets up the attribute change listener for the &quot;value&quot; 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">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   806     <span class="kw1">this</span>.<span class="me1">after</span><span class="br0">&#40;</span><span class="st0">&quot;valueChange&quot;</span><span class="sy0">,</span> <span class="kw1">this</span>._afterValueChange<span class="br0">&#41;</span><span class="sy0">;</span>
       
   807 &nbsp;
       
   808     <span class="kw2">var</span> boundingBox <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;boundingBox&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   809 &nbsp;
       
   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">&#40;</span><span class="sy0">!</span>Y.<span class="me1">UA</span>.<span class="me1">opera</span><span class="br0">&#41;</span> <span class="sy0">?</span> <span class="st0">&quot;down:&quot;</span> <span class="sy0">:</span> <span class="st0">&quot;press:&quot;</span><span class="sy0">;</span>
       
   813     keyEventSpec <span class="sy0">+=</span> <span class="st0">&quot;38, 40, 33, 34&quot;</span><span class="sy0">;</span>
       
   814 &nbsp;
       
   815 &nbsp;
       
   816     Y.<span class="me1">on</span><span class="br0">&#40;</span><span class="st0">&quot;change&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onInputChange<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">inputNode</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   817     Y.<span class="me1">on</span><span class="br0">&#40;</span><span class="st0">&quot;key&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onDirectionKey<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> boundingBox<span class="sy0">,</span> keyEventSpec<span class="br0">&#41;</span><span class="sy0">;</span>
       
   818     Y.<span class="me1">on</span><span class="br0">&#40;</span><span class="st0">&quot;mousedown&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onMouseDown<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> boundingBox<span class="br0">&#41;</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">&#40;</span><span class="st0">&quot;mouseup&quot;</span><span class="sy0">,</span> Y.<span class="me1">bind</span><span class="br0">&#40;</span><span class="kw1">this</span>._onDocMouseUp<span class="sy0">,</span> <span class="kw1">this</span><span class="br0">&#41;</span><span class="sy0">,</span> 
       
   820                 boundingBox.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;ownerDocument&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   821 <span class="br0">&#125;</span><span class="sy0">,</span>
       
   822 &nbsp;
       
   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">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   828     <span class="kw1">this</span>._uiSetValue<span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   829 <span class="br0">&#125;</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">&nbsp;* value attribute change listener. Updates the </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* value in the rendered input box, whenever the </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* attribute value changes.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">_afterValueChange <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    <span class="kw1">this</span>._uiSetValue<span class="br0">&#40;</span>e.<span class="me1">newVal</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li2"><div class="de2"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* Updates the value of the input box to reflect </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* the value passed in</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">_uiSetValue <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> val<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* value attribute default validator. Verifies that</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* the value being set lies between the min/max value</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">_validateValue<span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;min&quot;</span><span class="br0">&#41;</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">&#40;</span><span class="st0">&quot;max&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1">    <span class="kw1">return</span> <span class="br0">&#40;</span>Lang.<span class="me1">isNumber</span><span class="br0">&#40;</span>val<span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> val <span class="sy0">&amp;</span>gt<span class="sy0">;=</span> min <span class="sy0">&amp;&amp;</span> val <span class="sy0">&amp;</span>lt<span class="sy0">;=</span> max<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</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">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   900     <span class="kw1">this</span>._uiSetValue<span class="br0">&#40;</span>e.<span class="me1">newVal</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   901 <span class="br0">&#125;</span><span class="sy0">,</span>
       
   902 &nbsp;
       
   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">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   908     <span class="kw1">this</span>.<span class="me1">inputNode</span>.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> val<span class="br0">&#41;</span><span class="sy0">;</span>
       
   909 <span class="br0">&#125;</span><span class="sy0">,</span>
       
   910 &nbsp;
       
   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">&#40;</span>val<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;min&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span>
       
   917         max <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;max&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   918 &nbsp;
       
   919     <span class="kw1">return</span> <span class="br0">&#40;</span>Lang.<span class="me1">isNumber</span><span class="br0">&#40;</span>val<span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> val <span class="sy0">&amp;</span>gt<span class="sy0">;=</span> min <span class="sy0">&amp;&amp;</span> val <span class="sy0">&amp;</span>lt<span class="sy0">;=</span> max<span class="br0">&#41;</span><span class="sy0">;</span>
       
   920 <span class="br0">&#125;</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 &gt;= min && val &lt;= 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">&nbsp;* Creates the input field for the spinner and adds it to</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* the widget's content box, if not already in the markup.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li2"><div class="de2">_renderInput <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;contentBox&quot;</span><span class="br0">&#41;</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">&#40;</span><span class="st0">&quot;.&quot;</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">&#41;</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">&#40;</span><span class="st0">&quot;strings&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li2"><div class="de2">    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>input<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">        input <span class="sy0">=</span> Node.<span class="me1">create</span><span class="br0">&#40;</span>Spinner.<span class="me1">INPUT_TEMPLATE</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">        contentBox.<span class="me1">appendChild</span><span class="br0">&#40;</span>input<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    <span class="br0">&#125;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li2"><div class="de2">    input.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;title&quot;</span><span class="sy0">,</span> strings.<span class="me1">tooltip</span><span class="br0">&#41;</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">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* Creates the button controls for the spinner and add them to</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* the widget's content box, if not already in the markup.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">_renderButtons <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;contentBox&quot;</span><span class="br0">&#41;</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">&#40;</span><span class="st0">&quot;strings&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#40;</span>strings.<span class="me1">increment</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;increment&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</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">&#40;</span>strings.<span class="me1">decrement</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;decrement&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#40;</span>inc<span class="br0">&#41;</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">&#40;</span>dec<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* Utility method, to create a spinner button</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">_createButton <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>text<span class="sy0">,</span> className<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#40;</span>Spinner.<span class="me1">BTN_TEMPLATE</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">    btn.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;innerHTML&quot;</span><span class="sy0">,</span> text<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    btn.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;title&quot;</span><span class="sy0">,</span> text<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    btn.<span class="me1">addClass</span><span class="br0">&#40;</span>className<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#125;</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">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;contentBox&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span>
       
   959         input <span class="sy0">=</span> contentBox.<span class="me1">one</span><span class="br0">&#40;</span><span class="st0">&quot;.&quot;</span> <span class="sy0">+</span> Spinner.<span class="me1">INPUT_CLASS</span><span class="br0">&#41;</span><span class="sy0">,</span>
       
   960         strings <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;strings&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   961 &nbsp;
       
   962     <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>input<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   963         input <span class="sy0">=</span> Node.<span class="me1">create</span><span class="br0">&#40;</span>Spinner.<span class="me1">INPUT_TEMPLATE</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   964         contentBox.<span class="me1">appendChild</span><span class="br0">&#40;</span>input<span class="br0">&#41;</span><span class="sy0">;</span>
       
   965     <span class="br0">&#125;</span>
       
   966 &nbsp;
       
   967     input.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;title&quot;</span><span class="sy0">,</span> strings.<span class="me1">tooltip</span><span class="br0">&#41;</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">&#125;</span><span class="sy0">,</span>
       
   970 &nbsp;
       
   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">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="st0">&quot;contentBox&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span>
       
   977         strings <span class="sy0">=</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;strings&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   978 &nbsp;
       
   979     <span class="kw2">var</span> inc <span class="sy0">=</span> <span class="kw1">this</span>._createButton<span class="br0">&#40;</span>strings.<span class="me1">increment</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;increment&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</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">&#40;</span>strings.<span class="me1">decrement</span><span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;decrement&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   981 &nbsp;
       
   982     <span class="kw1">this</span>.<span class="me1">incrementNode</span> <span class="sy0">=</span> contentBox.<span class="me1">appendChild</span><span class="br0">&#40;</span>inc<span class="br0">&#41;</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">&#40;</span>dec<span class="br0">&#41;</span><span class="sy0">;</span>
       
   984 <span class="br0">&#125;</span><span class="sy0">,</span>
       
   985 &nbsp;
       
   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">&#40;</span>text<span class="sy0">,</span> className<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
   990 &nbsp;
       
   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">&#40;</span>Spinner.<span class="me1">BTN_TEMPLATE</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
   992     btn.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;innerHTML&quot;</span><span class="sy0">,</span> text<span class="br0">&#41;</span><span class="sy0">;</span>
       
   993     btn.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;title&quot;</span><span class="sy0">,</span> text<span class="br0">&#41;</span><span class="sy0">;</span>
       
   994     btn.<span class="me1">addClass</span><span class="br0">&#40;</span>className<span class="br0">&#41;</span><span class="sy0">;</span>
       
   995 &nbsp;
       
   996     <span class="kw1">return</span> btn<span class="sy0">;</span>
       
   997 <span class="br0">&#125;</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">&nbsp;* Bounding box Arrow up/down, Page up/down key listener.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* Increments/Decrement the spinner value, based on the key pressed.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li1"><div class="de1">_onDirectionKey <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    e.<span class="me1">preventDefault</span><span class="br0">&#40;</span><span class="br0">&#41;</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">&#40;</span>e.<span class="me1">charCode</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;max&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</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">&#40;</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;min&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</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">&#125;</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1">    <span class="kw1">if</span> <span class="br0">&#40;</span>newVal <span class="sy0">!==</span> currVal<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">        <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> newVal<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    <span class="br0">&#125;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* Bounding box mouse down handler. Will determine if the mouse down</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* is on one of the spinner buttons, and increment/decrement the value</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* accordingly.</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* </span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* 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">&nbsp;* 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">&nbsp;* is detected.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li2"><div class="de2">_onMouseDown <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span>node.<span class="me1">hasClass</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;increment&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">        <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> currVal <span class="sy0">+</span> minorStep<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">        ...</div></li><li class="li1"><div class="de1">    <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>node.<span class="me1">hasClass</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;decrement&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">        <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> currVal <span class="sy0">-</span> minorStep<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">        ...</div></li><li class="li1"><div class="de1">    <span class="br0">&#125;</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1">    <span class="kw1">if</span> <span class="br0">&#40;</span>handled<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">        <span class="kw1">this</span>._setMouseDownTimers<span class="br0">&#40;</span>dir<span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    <span class="br0">&#125;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* Document mouse up handler. Clears the timers supporting</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;* the &quot;mouse held down&quot; behavior.</span></div></li><li class="li1"><div class="de1"><span class="coMULTI">&nbsp;*/</span></div></li><li class="li2"><div class="de2">_onDocMouseUp <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    <span class="kw1">this</span>._clearMouseDownTimers<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span><span class="sy0">,</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/*</span></div></li><li class="li2"><div class="de2"><span class="coMULTI">&nbsp;* 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">&nbsp;*/</span></div></li><li class="li1"><div class="de1">_onInputChange <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="kw1">this</span>._validateValue<span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">inputNode</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">    <span class="br0">&#125;</span></div></li><li class="li1"><div class="de1"><span class="br0">&#125;</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">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
  1057     e.<span class="me1">preventDefault</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
  1058     ...
       
  1059     <span class="kw1">switch</span> <span class="br0">&#40;</span>e.<span class="me1">charCode</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;max&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</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">&#40;</span>newVal<span class="sy0">,</span> <span class="kw1">this</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;min&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
  1073             <span class="kw1">break</span><span class="sy0">;</span>
       
  1074     <span class="br0">&#125;</span>
       
  1075 &nbsp;
       
  1076     <span class="kw1">if</span> <span class="br0">&#40;</span>newVal <span class="sy0">!==</span> currVal<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
  1077         <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> newVal<span class="br0">&#41;</span><span class="sy0">;</span>
       
  1078     <span class="br0">&#125;</span>
       
  1079 <span class="br0">&#125;</span><span class="sy0">,</span>
       
  1080 &nbsp;
       
  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">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span>node.<span class="me1">hasClass</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;increment&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
  1094         <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> currVal <span class="sy0">+</span> minorStep<span class="br0">&#41;</span><span class="sy0">;</span>
       
  1095         ...
       
  1096     <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="kw1">if</span> <span class="br0">&#40;</span>node.<span class="me1">hasClass</span><span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;decrement&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
  1097         <span class="kw1">this</span>.<span class="me1">set</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="sy0">,</span> currVal <span class="sy0">-</span> minorStep<span class="br0">&#41;</span><span class="sy0">;</span>
       
  1098         ...
       
  1099     <span class="br0">&#125;</span>
       
  1100 &nbsp;
       
  1101     <span class="kw1">if</span> <span class="br0">&#40;</span>handled<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
  1102         <span class="kw1">this</span>._setMouseDownTimers<span class="br0">&#40;</span>dir<span class="br0">&#41;</span><span class="sy0">;</span>
       
  1103     <span class="br0">&#125;</span>
       
  1104 <span class="br0">&#125;</span><span class="sy0">,</span>
       
  1105 &nbsp;
       
  1106 <span class="coMULTI">/*
       
  1107  * Document mouse up handler. Clears the timers supporting
       
  1108  * the &quot;mouse held down&quot; behavior.
       
  1109  */</span>
       
  1110 _onDocMouseUp <span class="sy0">:</span> <span class="kw2">function</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
  1111     <span class="kw1">this</span>._clearMouseDownTimers<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
  1112 <span class="br0">&#125;</span><span class="sy0">,</span>
       
  1113 &nbsp;
       
  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">&#40;</span>e<span class="br0">&#41;</span> <span class="br0">&#123;</span>
       
  1118     <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="kw1">this</span>._validateValue<span class="br0">&#40;</span><span class="kw1">this</span>.<span class="me1">inputNode</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&quot;value&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</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">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
  1121     <span class="br0">&#125;</span>
       
  1122 <span class="br0">&#125;</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">&#40;</span>Spinner.<span class="kw3">NAME</span><span class="sy0">,</span> <span class="st0">&quot;value&quot;</span><span class="br0">&#41;</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">&#40;</span><span class="st0">&quot;increment&quot;</span><span class="br0">&#41;</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">&#40;</span>Spinner.<span class="kw3">NAME</span><span class="sy0">,</span> <span class="st0">&quot;value&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
  1201 ...
       
  1202 <span class="kw1">this</span>.<span class="me1">getClassName</span><span class="br0">&#40;</span><span class="st0">&quot;increment&quot;</span><span class="br0">&#41;</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">&#123;</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">&#125;</span></div></li><li class="li2"><div class="de2">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/* Bounding Box - Set the bounding box to be &quot;inline block&quot; for spinner */</span></div></li><li class="li1"><div class="de1"><span class="re1">.yui-spinner</span> <span class="br0">&#123;</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">&#125;</span></div></li><li class="li1"><div class="de1">&nbsp;</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">&#123;</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">&#125;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/* Input Text Box, generated through getClassName(&quot;value&quot;) */</span></div></li><li class="li2"><div class="de2"><span class="re1">.yui-spinner-value</span> <span class="br0">&#123;</span></div></li><li class="li1"><div class="de1">    ...</div></li><li class="li1"><div class="de1"><span class="br0">&#125;</span></div></li><li class="li1"><div class="de1">&nbsp;</div></li><li class="li1"><div class="de1"><span class="coMULTI">/* Button controls, generated through getClassName(&quot;increment&quot;) */</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">&#123;</span></div></li><li class="li1"><div class="de1">    ...</div></li><li class="li1"><div class="de1"><span class="br0">&#125;</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">&#123;</span>
       
  1216     <span class="kw1">display</span><span class="sy0">:</span><span class="kw2">none</span><span class="sy0">;</span>
       
  1217 <span class="br0">&#125;</span>
       
  1218 &nbsp;
       
  1219 <span class="coMULTI">/* Bounding Box - Set the bounding box to be &quot;inline block&quot; for spinner */</span>
       
  1220 <span class="re1">.yui-spinner</span> <span class="br0">&#123;</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">&#125;</span>
       
  1226 &nbsp;
       
  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">&#123;</span>
       
  1229     <span class="kw1">padding</span><span class="sy0">:</span><span class="re3">1px</span><span class="sy0">;</span>
       
  1230 <span class="br0">&#125;</span>
       
  1231 &nbsp;
       
  1232 <span class="coMULTI">/* Input Text Box, generated through getClassName(&quot;value&quot;) */</span>
       
  1233 <span class="re1">.yui-spinner-value</span> <span class="br0">&#123;</span>
       
  1234     ...
       
  1235 <span class="br0">&#125;</span>
       
  1236 &nbsp;
       
  1237 <span class="coMULTI">/* Button controls, generated through getClassName(&quot;increment&quot;) */</span>
       
  1238 <span class="re1">.yui-spinner-increment</span><span class="sy0">,</span> <span class="re1">.yui-spinner-decrement</span> <span class="br0">&#123;</span>
       
  1239     ...
       
  1240 <span class="br0">&#125;</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">&lt;<span class="kw2">div</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;numberField&quot;</span>&gt;</span></div></li><li class="li1"><div class="de1">    <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text&quot;</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;yui-spinner-value&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;20&quot;</span> <span class="sy0">/</span>&gt;</span></div></li><li class="li1"><div class="de1"><span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</span></div></li></ol></pre></div><div class="nonumbers"><pre class="html4strict" style="font-family:monospace;"><span class="sc2">&lt;<span class="kw2">div</span> <span class="kw3">id</span><span class="sy0">=</span><span class="st0">&quot;numberField&quot;</span>&gt;</span>
       
  1272     <span class="sc2">&lt;<span class="kw2">input</span> <span class="kw3">type</span><span class="sy0">=</span><span class="st0">&quot;text&quot;</span> <span class="kw3">class</span><span class="sy0">=</span><span class="st0">&quot;yui-spinner-value&quot;</span> <span class="kw3">value</span><span class="sy0">=</span><span class="st0">&quot;20&quot;</span> <span class="sy0">/</span>&gt;</span>
       
  1273 <span class="sc2">&lt;<span class="sy0">/</span><span class="kw2">div</span>&gt;</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">&#40;</span><span class="br0">&#123;</span></div></li><li class="li2"><div class="de2">    contentBox<span class="sy0">:</span> <span class="st0">&quot;#numberField&quot;</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">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li1"><div class="de1">spinner.<span class="me1">render</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li><li class="li2"><div class="de2">spinner.<span class="kw3">focus</span><span class="br0">&#40;</span><span class="br0">&#41;</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">&#40;</span><span class="br0">&#123;</span>
       
  1282     contentBox<span class="sy0">:</span> <span class="st0">&quot;#numberField&quot;</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">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
  1286 spinner.<span class="me1">render</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
       
  1287 spinner.<span class="kw3">focus</span><span class="br0">&#40;</span><span class="br0">&#41;</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 &amp; Drop - Functional Examples" href="../../examples/dd/index.html">Drag &amp; 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 &copy; 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>