Source: src/main/javascript/oracle/oj/ojinputnumber/ojinputnumber.js

Oracle® JavaScript Extension Toolkit (JET)
1.1.2

E65298-01

/**
 * Copyright (c) 2014, Oracle and/or its affiliates.
 * All rights reserved.
 */

/**
 * @preserve Copyright 2013 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

// jeanne retrieved from https://raw.github.com/jquery/jquery-ui/1-10-stable/ui/jquery.ui.spinner.js on 6/2013, and then modified

/*!
 * JET InputNumber @VERSION
 *
 *
 * Depends:
 *  jquery.ui.widget.js
 */

/**
 * @ojcomponent oj.ojInputNumber
 * @augments oj.editableValue
 * @since 0.6
 * @classdesc
 * <h3 id="inputNumberOverview-section">
 *   JET InputNumber Component
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#inputNumberOverview-section"></a>
 * </h3>
 * <p>Description: The ojInputNumber component enhances a browser input element 
 * into one that holds numbers and it has a spinbox to quickly increment or 
 * decrement the number. The <code class="prettyprint">value</code> option must be a number and must 
 * be within the <code class="prettyprint">min</code> and <code class="prettyprint">max</code> range. 
 * </p>
 * <p>A step mismatch is when
 * the value is not a multiple of <code class="prettyprint">step</code>, 
 * starting at the <code class="prettyprint">min</code> 
 * or 0 if no <code class="prettyprint">min</code> is set.
 * A step mismatch will not be flagged as a validation error by default, but
 * the step up and step down feature will change the value to be a step match
 * if it isn't already.
 * </p>
 * 
 * <h3 id="touch-section">
 *   Touch End User Information
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#touch-section"></a>
 * </h3>
 *
 * {@ojinclude "name":"touchDoc"}
 *
 *
 * <h3 id="keyboard-section">
 *   Keyboard End User Information
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#keyboard-section"></a>
 * </h3>
 *
 * {@ojinclude "name":"keyboardDoc"}
 *
 *
 * <h3 id="a11y-section">
 *   Accessibility
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#a11y-section"></a>
 * </h3>
 * <p>
 * The component is accessible; it sets and maintains the appropriate aria- attributes, 
 * like aria-valuenow, aria-valuemax, aria-valuemin and aria-valuetext.
 * </p>
 * <p>
 * It is up to the application developer to associate the label to the input component.
 * For inputNumber, you should put an <code class="prettyprint">id</code> on the input, and then set 
 * the <code class="prettyprint">for</code> attribute on the label to be the input's id.
 * </p>
 * <p>Disabled content: JET supports an accessible luminosity contrast ratio, 
 * as specified in <a href="http://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast">WCAG 2.0 - Section 1.4.3 "Contrast"</a>, 
 * in the themes that are accessible.  (See the "Theming" chapter of the JET Developer Guide for more information on which 
 * themes are accessible.)  Note that Section 1.4.3 says that text or images of text that are part of an inactive user 
 * interface component have no contrast requirement.  Because disabled content may not meet the minimum contrast ratio 
 * required of enabled content, it cannot be used to convey meaningful information.<p>
 * <h3 id="label-section">
 *   Label and InputNumber
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#label-section"></a>
 * </h3>
 * <p>
 * For accessibility, you should associate a label element with the input
 * by putting an <code class="prettyprint">id</code> on the input, and then setting the 
 * <code class="prettyprint">for</code> attribute on the label to be the input's id.
 * </p>
 * <p>
 * The component will decorate its associated label with required and help 
 * information, if the <code class="prettyprint">required</code> and <code class="prettyprint">help</code> options are set. 
 * </p>
 * <h3 id="state-section">
 *   Setting the Value Option
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#state-section"></a>
 * </h3>
 * <p>If the value option is undefined, 
 * then the DOM value property is used, if any; else it is null.</p>
 * <p>The value option (if it is not null or undefined) 
 * is coerced (+ val). e.g., "123a" is coerced to NaN</p>
 * <p>To clear out the value option, you can set it to null.
 * <code class="prettyprint">$(".selector").ojInputNumber("option", "value", null);</code>
 * </p>
 *
 * <!-- - - - - Above this point, the tags are for the class.
 *              Below this point, the tags are for the constructor (initializer). - - - - - - -->
 * @desc Creates an ojInputNumber component
 * 
 * @param {Object=} options a map of option-value pairs to set on the component
 * 
 * @example <caption>Initialize component using widget API</caption>
 * <input id="spin" type="text"/><br/>
 * $("#spin").ojInputNumber({'value': 10, 'max':100, 'min':0, 'step':2});
 * $("#spin").ojInputNumber({'option', 'value', 10});
 * @example <caption>Using knockout, value, min, max bind to observables - salary, salaryMax, salaryMin</caption> 
 * <input id="foo" data-bind="ojComponent: 
 *   {component: 'ojInputNumber', value: salary, min:salaryMin, max:salaryMax, step:5}"/>
 */
oj.__registerWidget("oj.ojInputNumber", $['oj']['editableValue'],
{
  version: "1.0.0",
  defaultElement: "<input>",
  widgetEventPrefix: "oj",
  options:
  {
    // TODO: revisit
    // It's expensive to create a default converter ahead of time when a page author can set a custom 
    // one for if they do this will be promptly discarded. 
    
    /** 
     * A number converter instance that duck types {@link oj.NumberConverter}. Or an object literal 
     * containing the properties listed below. 
     * <p>
     * When <code class="prettyprint">converter</code> option changes due to programmatic 
     * intervention, the component performs various tasks based on the current state it is in. </br>
     * 
     * <h4>Steps Performed Always</h4>
     * <ul>
     * <li>Any cached converter instance is cleared and new converter created. The converter hint is 
     * pushed to messaging. E.g., notewindow displays the new hint(s).
     * </li>
     * </ul>
     * 
     * <h4>Running Validation</h4>
     * <ul>
     * <li>if component is valid when <code class="prettyprint">converter</code> option changes, the 
     * display value is refreshed.</li>
     * <li>if component is invalid and is showing messages -
     * <code class="prettyprint">messagesShown</code> option is non-empty, when 
     * <code class="prettyprint">converter</code> option changes, then all messages generated by the 
     * component are cleared and full validation run using its current display value. 
     * <ul>
     *   <li>if there are validation errors, then <code class="prettyprint">value</code> 
     *   option is not updated, and the errors pushed to <code class="prettyprint">messagesShown</code>
     *   option. The display value is not refreshed in this case. </li>
     *   <li>if no errors result from the validation, <code class="prettyprint">value</code> 
     *   option is updated; page author can listen to the <code class="prettyprint">optionChange</code> 
     *   event on the <code class="prettyprint">value</code> option to clear custom errors. The 
     *   display value is refreshed with the formatted value provided by converter.</li>
     * </ul>
     * </li>
     * <li>if component is invalid and has deferred messages -  
     * <code class="prettyprint">messagesHidden</code> option is non-empty, when 
     * <code class="prettyprint">converter</code> option changes, then the display value is 
     * refreshed with the formatted value provided by converter.</li>
     * </ul>
     * </p>
     * 
     * <h4>Clearing Messages</h4>
     * <ul>
     * <li>When component messages are cleared in the cases described above, messages created by 
     * the component that are present in both <code class="prettyprint">messagesHidden</code> and 
     * <code class="prettyprint">messagesShown</code> options are cleared.</li>
     * <li><code class="prettyprint">messagesCustom</code> option is not cleared. Page authors can 
     * choose to clear it explicitly when setting the converter option.</li>
     * </ul>
     * </p>
     * 
     * @property {string} type - the converter type registered with the oj.ConverterFactory. 
     * Usually 'number'. See {@link oj.NumberConverterFactory} for details. <br/>
     * E.g., <code class="prettyprint">{converter: {type: 'number'}</code>
     * @property {Object=} options - optional Object literal of options that the converter expects. 
     * See {@link oj.IntlNumberConverter} for options supported by the jet number converter. 
     * E.g., <code class="prettyprint">{converter: {type: 'number', options: {style: 'decimal'}}</code>
     * 
     * @example <caption>Initialize component to use default converter</caption>
     * $(".selector").ojInputNumber({value: 25000});
     * 
     * @example <caption>Initialize the component with a number converter instance:</caption>
     * // Initialize converter instance using currency options
     * var options = {style: 'currency', 'currency': 'USD', maximumFractionDigits: 0};
     * var numberConverterFactory = oj.Validation.converterFactory("number");
     * var salaryConverter = numberConverterFactory.createConverter(options);<br/>
     * // set converter instance using converter option
     * $(".selector").ojInputNumber({ 
     *   value: 25000,
     *   converter: salaryConverter
     * });
     * 
     * @example <caption>Initialize the component with converter object literal:</caption>
     * $(".selector").ojInputNumber({
     *   value: 25000,
     *   converter: {
     *     type: 'number', 
     *     options : {
     *       style: 'currency', 
     *       currency: 'USD', 
     *       maximumFractionDigits: 0
     *     }
     *   }
     * });
     * 
     * @example <caption>Change the converter option:</caption>
     * // new converter instance 
     * var options = {style: 'currency', currency: 'USD', 'currencyDisplay': 'name', maximumFractionDigits: 2};
     * var numberConverterFactory = oj.Validation.converterFactory("number");
     * var salaryConverter = numberConverterFactory.createConverter(options);<br/>
     * // set converter instance using converter option
     * $(".selector").ojInputNumber("option", "converter", salaryConverter);
     * 
     * 
     * @default <code class="prettyprint">oj.Validation.converterFactory(oj.ConverterFactory.CONVERTER_TYPE_NUMBER).createConverter()</code>. 
     * When initialized with no options, the default options for the current locale are assumed.
     * 
     * @expose 
     * @access public
     * @instance
     * @memberof oj.ojInputNumber
     * @type {Object}
     */    
    converter: oj.Validation.converterFactory(
            oj.ConverterFactory.CONVERTER_TYPE_NUMBER).createConverter(),

    /** 
     * The maximum allowed value. This number is used in the range validator; if the 
     * <code class="prettyprint">value</code> is greater than the <code class="prettyprint">max</code>,
     * then the range validator flags an error to the user. The up arrow
     *  is disabled when the maximum value is reached. 
     *  <p>
     * The element's <code class="prettyprint">max</code> attribute is used if it 
     * exists and the option is not explicitly set.
     * <p>
     *  <code class="prettyprint">Max</code> must be a
     *  <code class="prettyprint">number</code> or <code class="prettyprint">null</code>; 
     *  <code class="prettyprint">null</code> indicates no maximum. If not null, 
     *  the <code class="prettyprint">max</code> option value will be coerced (+). 
     *  If the coerced value is <code class="prettyprint">NaN</code>, 
     *  an <code class="prettyprint">Error</code> is thrown.
     * <p>
     * The <code class="prettyprint">max</code> must not be less than the 
     * <code class="prettyprint">min</code>, else an Error is thrown during initialization.
     * @expose 
     * @memberof oj.ojInputNumber
     * @instance
     * @type {?number}
     * @default <code class="prettyprint">null</code>
     * @example <caption>Initialize the inputNumber with the 
     * <code class="prettyprint">max</code> option specified:</caption>
     * $( ".selector" ).ojInputNumber( { "max": 100 } );
     * @example <caption>Change the 
     * <code class="prettyprint">max</code> option to a float:</caption>
     * $( ".selector" ).ojInputNumber("option", "max", 100.5);
     * @example <caption>To remove the maximum range restriction from inputNumber:</caption>
     * $( ".selector" ).ojInputNumber( { "max": null } );
     * @example <caption>Set the <code class="prettyprint">max</code> to a non-number 
     * which will throw an Error:</caption>
     * $( ".selector" ).ojInputNumber( { "max": "123abc" } );
     * $( ".selector" ).ojInputNumber( { "max": "abc123" } );
     * @example <caption>Set the <code class="prettyprint">max</code> to a number inside 
     * of quotes; this is valid and will be coerced to a number,
     * -100 in this example:</caption>
     * $( ".selector" ).ojInputNumber( { "max": "-100" } );
     */
    max: null,
    
    /** 
     * The minimum allowed value. This number is used in the range validator; if the 
     * <code class="prettyprint">value</code> is less than the <code class="prettyprint">min</code>,
     * then the range validator flags an error to the user. The down arrow
     *  is disabled when the minimum value is reached. 
     *  <p>
     * The element's <code class="prettyprint">min</code> attribute is used if it 
     * exists and the option is not explicitly set.
     * <p>
     *  <code class="prettyprint">Min</code> must be a
     *  <code class="prettyprint">number</code> or <code class="prettyprint">null</code>; 
     *  <code class="prettyprint">null</code> indicates no minimum. If not null, 
     *  the <code class="prettyprint">min</code> option value will be coerced (+). 
     *  If the coerced value is <code class="prettyprint">NaN</code>, 
     *  an <code class="prettyprint">Error</code> is thrown.
     * <p>
     * The <code class="prettyprint">max</code> must not be less than the 
     * <code class="prettyprint">min</code>, else an Error is thrown during initialization.
     * @expose 
     * @memberof oj.ojInputNumber
     * @instance
     * @type {?number}
     * @default <code class="prettyprint">null</code>
     * @example <caption>Initialize the inputNumber with the 
     * <code class="prettyprint">min</code> option specified:</caption>
     * $( ".selector" ).ojInputNumber( { "min": -100 } );
     * @example <caption>Change the 
     * <code class="prettyprint">min</code> option to a float:</caption>
     * $( ".selector" ).ojInputNumber("option", "min", 1.5);
     * @example <caption>To remove the minimum range restriction from inputNumber:</caption>
     * $( ".selector" ).ojInputNumber( { "min": null } );
     * @example <caption>Set the <code class="prettyprint">min</code> to a non-number 
     * which will throw an Error:</caption>
     * $( ".selector" ).ojInputNumber( { "min": "123abc" } );
     * $( ".selector" ).ojInputNumber( { "min": "abc123" } );
     * @example <caption>Set the <code class="prettyprint">min</code> to a number inside 
     * of quotes; this is valid and will be coerced to a number,
     * -100 in this example:</caption>
     * $( ".selector" ).ojInputNumber( { "min": "-100" } );
     */
    min: null,
  
    /**
     * The placeholder text to set on the element. Though it is possible to set placeholder 
     * attribute on the element itself, the component will only read the value when the component
     * is created. Subsequent changes to the element's placeholder attribute will not be picked up 
     * and page authors should update the option directly.
     * 
     * @example <caption>Initialize the component with the <code class="prettyprint">placeholder</code> option:</caption>
     * <input id="number" data-bind="ojComponent: {
     *   component: 'ojInputNumber', placeholder: 'Please enter a number'}" />
     * 
     * @example <caption>Initialize <code class="prettyprint">placeholder</code> option from html attribute:</caption>
     * <input id="number" data-bind="ojComponent: {component: 'ojInputNumber'}" 
     *   placeholder="Please enter a number" />
     * 
     * @default when the option is not set, the element's placeholder attribute is used if it exists. 
     * If the attribute is not set then the default can be a converter hint. See displayOptions for 
     * details.
     * 
     * @expose 
     * @instance
     * @memberof oj.ojInputNumber
     * @type {string|null|undefined}
     */
    placeholder: undefined,
    /**
     * <p>The  <code class="prettyprint">rawValue</code> is the read-only option for retrieving 
     * the current value from the input field in text form.</p>
     * <p>
     * The <code class="prettyprint">rawValue</code> updates on the 'input' javascript event, 
     * so the <code class="prettyprint">rawValue</code> changes as the value of the input is changed. 
     * If the user types in '1,200' into the field, the rawValue will be '1', then '1,', then '1,2', 
     * ..., and finally '1,200'. Then when the user blurs or presses Enter 
     * the <code class="prettyprint">value</code> option gets updated.
     * </p>
     * <p>This is a read-only option so page authors cannot set or change it directly.</p>
     * @expose 
     * @access public
     * @instance
     * @default n/a
     * @memberof oj.ojInputNumber
     * @type {string|undefined}
     * @since 1.2
     * @readonly
     */
    rawValue: undefined,    
    /** 
     * Whether the component is readOnly. The element's <code class="prettyprint">readOnly</code>
     *  property is used as its initial 
     * value if it exists, when the option is not explicitly set. When neither is set, 
     * <code class="prettyprint">readOnly </code>
     * defaults to false.
     * 
     * @example <caption>Initialize component with <code class="prettyprint">readOnly</code> option:</caption>
     * $(".selector").ojInputNumber({"readOnly": true});
     * 
     * @expose 
     * @type {?boolean}
     * @default <code class="prettyprint">false</code>
     * @instance
     * @memberof oj.ojInputNumber
     */
    readOnly: false,
    
    /** 
     * The size of the step to take when spinning via buttons or via the 
     * <code class="prettyprint">stepUp()</code>/<code class="prettyprint">stepDown()</code> methods. 
     * The element's <code class="prettyprint">step</code> attribute is used if it 
     * exists and the option is not explicitly set. Step must be a 
     * <code class="prettyprint">number</code>
     * greater than 0, otherwise an exception is thrown. It defaults to 
     * <code class="prettyprint">1</code> if nothing, or <code class="prettyprint">null</code>, is specified.
     *  If not null, the <code class="prettyprint">step</code> option value will be 
     *  coerced (+). 
     *  If the coerced value is <code class="prettyprint">NaN</code>, 
     *  an <code class="prettyprint">Error</code> is thrown.
     * <p>
     * The step up and step down feature will change the value to be a step match if it isn't already.
     * A step match is when the value is a multiple of step, starting at the 
     * <code class="prettyprint">min</code> or <code class="prettyprint">0</code> if no 
     * <code class="prettyprint">min</code> is set.
     * A value can be a step mismatch; if the <code class="prettyprint">value</code> is set 
     * to be a step mismatch, it will not be flagged as a validation error.
     * @expose 
     * @instance
     * @type {?number}
     * @default <code class="prettyprint">1</code>
     * @memberof oj.ojInputNumber 
     * @example <caption>Initialize the inputNumber with the 
     * <code class="prettyprint">step</code> option specified:</caption>
     * $( ".selector" ).ojInputNumber( { "step": 10 } );
     * @example <caption>Change the 
     * <code class="prettyprint">step</code> option to a float:</caption>
     * $( ".selector" ).ojInputNumber("option", "step", 0.5);
     * @example <caption>Set the <code class="prettyprint">step</code> to a non-number 
     * which will throw an Error:</caption>
     * $( ".selector" ).ojInputNumber( { "step": "123abc" } );
     * $( ".selector" ).ojInputNumber( { "step": "abc123" } );
     * @example <caption>Set the <code class="prettyprint">step</code> to a number inside 
     * of quotes; this is valid and will be coerced to a number,
     * 10 in this example:</caption>
     * $( ".selector" ).ojInputNumber( { "step": "10" } );
     * */
    step: 1,
    /** 
     * The value of the component. Value should be a number. 
     * 
     * <p>
     * When <code class="prettyprint">value</code> option changes due to programmatic 
     * intervention, the component always clears all messages and runs deferred validation, and 
     * always refreshes UI display value. If the value cannot be coerced to a number, an
     * Error is thrown.</br>
     * 
     * <h4>Clearing Messages</h4>
     * <ul>
     * <li>All messages are cleared. This includes  
     * <code class="prettyprint">messagesHidden</code>, <code class="prettyprint">messagesShown</code>
     *  and <code class="prettyprint">messagesCustom</code> options.</li>
     * </ul>
     * 
     *  
     * <h4>Running Validation</h4>
     * <ul>
     * <li>component always runs deferred validation; if there is a validation error the 
     * <code class="prettyprint">messagesHidden</code> option is updated.</li>
     * </ul>
     * </p>
     * 
     * @example <caption>Initialize the component with the <code class="prettyprint">value</code> option specified:</caption>
     * $(".selector").ojInputNumber({'value': 55});<br/>
     * @example <caption>Get or set <code class="prettyprint">value</code> option, after initialization:</caption>
     * // Getter: returns 55
     * $(".selector").ojInputNumber("option", "value");
     * // Setter: sets 20
     * $(".selector").ojInputNumber("option", "value", 20);
     * @example <caption>Set the <code class="prettyprint">value</code> to a non-number 
     * which will throw an Error:</caption>
     * $( ".selector" ).ojInputNumber( { "value": "123abc" } );
     * $( ".selector" ).ojInputNumber( { "value": "abc123" } );
     * @example <caption>Set the <code class="prettyprint">value</code> to a number inside 
     * of quotes; this is valid and will be coerced to a number,
     * 10 in this example:</caption>
     * $( ".selector" ).ojInputNumber( { "value": "10" } );
     * @example <caption>Set the <code class="prettyprint">value</code> to an empty string; 
     * this is valid and value is coerced (+), to 0 in this example:</caption>
     * $( ".selector" ).ojInputNumber( { "value": "" } );
     * @expose 
     * @access public
     * @instance
     * @default <code class="prettyprint">null</code>
     * When the option is not set, the element's dom value is used as its initial value 
     * if it exists.
     * @memberof oj.ojInputNumber
     * @type {Object|null}
     */
    value: null
  },
  // P U B L I C    M E T H O D S

  getNodeBySubId: function(locator)
  {
    var node = this._superApply(arguments), subId;
    if (!node)
    {
      subId = locator['subId'];
      if (subId === "oj-inputnumber-up") {
        node = this.widget().find(".oj-inputnumber-up")[0];
      }
      if (subId === "oj-inputnumber-down") {
        node = this.widget().find(".oj-inputnumber-down")[0];
      }
      if (subId === "oj-inputnumber-input") {
        node = this.widget().find(".oj-inputnumber-input")[0];
      }
    }
    // Non-null locators have to be handled by the component subclasses
    return node || null;
 },
  /**
   * Refreshes the inputNumber component
   * <p>A <code class="prettyprint">refresh()</code> or re-init is required 
   * when an inputNumber is changed in a non-option way, like in the following circumstances:
   * <ul>
   *   <li>Button translations change.</li>
   * </ul>    
   * @expose 
   * @memberof oj.ojInputNumber
   * @instance
   * @example <caption>Invoke the <code class="prettyprint">refresh</code> method:</caption>
   * $( ".selector" ).ojInputNumber( "refresh" );
   */
  refresh: function() 
  {
    this._super();
    this._setup();
  },
  /**
   * <p>Decrements the value by the specified number of steps. 
   * Without the parameter, a single step is decremented.</p>
   <p>If the resulting value is above the max, below the min, 
   or results in a step mismatch, the value will be adjusted to the closest valid value.</p>
   * @param {Number} steps - Number of steps to decrement, defaults to 1.
   * @expose
   * @instance
   * @memberof oj.ojInputNumber 
   */
  stepDown: function(steps)
  {
    this._step(steps, false);
  },
   /**
   * <p>Increments the value by the specified number of steps. 
   * Without the parameter, a single step is incremented.</p>
   <p>If the resulting value is above the max, below the min, 
   or results in a step mismatch, the value will be adjusted to the closest valid value.</p>
   * @param {Number} steps - Number of steps to increment, defaults to 1.
   * @expose
   * @instance
   * @memberof oj.ojInputNumber 
   */
  stepUp: function(steps)
  {
    this._step(steps, true);
  },

  /**
   * Returns a jQuery object containing the element visually representing the inputnumber. 
   * 
   * <p>This method does not accept any arguments.
   * 
   * @expose
   * @memberof oj.ojInputNumber
   * @instance
   * @return {jQuery} the inputnumber
   */
  widget: function()
  {
    return this.uiInputNumber;
  },
  
  // P R O T E C T E D    C O N S T A N T S   A N D   M E T H O D S

  // *********** START WIDGET FACTORY METHODS (they retain _camelcase naming convention) **********
  
  
  /**
  * Called at component create time primarily to initialize options, often using DOM values. This 
  * method is called before _ComponentCreate is called, so components that override this method 
  * should be aware that the component has not been rendered yet. The element DOM is available and 
  * can be relied on to retrieve any default values. <p> 
  * @param {!Object} originalDefaults - original default options defined on the widget and its ancestors
  * @param {?Object} constructorOptions - options passed into the widget constructor
  * 
  * @memberof oj.ojInputNumber
  * @instance
  * @protected
  */
  _InitOptions: function(originalDefaults, constructorOptions)
  {
    var opts = this.options;
    var self = this;;

    var props = 
      [{attribute: "disabled", defaultOptionValue: false, validateOption: true},
      {attribute: "placeholder", defaultOptionValue: ""},
      {attribute: "value", defaultOptionValue: null}, // don't coerce here. I do it myself
      {attribute: "readonly", option: "readOnly", defaultOptionValue: false,
        validateOption: true},
      {attribute: "required", defaultOptionValue: false,
        coerceDomValue: true, validateOption: true},
      {attribute: "title", defaultOptionValue: ""},
      {attribute: "min", defaultOptionValue: null},
      {attribute: "max", defaultOptionValue: null},
      {attribute: "step", defaultOptionValue: 1}];

    this._superApply(arguments);

    oj.EditableValueUtils.initializeOptionsFromDom(props, constructorOptions, this,
      // post-process callback
      function (initializedOptions)
      { 
        // coerce regardless of where the option value came from - dom/constructor
        var toParse = ['value', 'step', 'min', 'max'];
        
        for (var i=0; i<toParse.length; i++)
        {
          var opt = toParse[i];
          var value = (opt in initializedOptions) ? initializedOptions[opt] : opts[opt];
          if (value != null)
          {
            if (opt === 'step')
              initializedOptions[opt] =  self._parseStep(value);
            else
              initializedOptions[opt] =  self._parse(opt, value);
          } 
        }
      }
    );
    
    if (opts['value'] === undefined)
    {
      throw new Error("ojInputNumber has no value");
    }
    
    // now make sure min < max, else throw an Error
    if (opts['min'] != null && opts['max'] != null)
    {
      if (opts['max'] < opts['min'])
      {
        throw new Error("ojInputNumber's max must not be less than min");
      }
    }
    
  },
  /**
   * After _ComponentCreate and _AfterCreate, 
   * the widget should be 100% set up. this._super should be called first.
   * @override
   * @protected
   * @instance
   * @memberof oj.ojInputNumber
   */
  _ComponentCreate: function()
  {
    var node = this.element;
    this._super();

    this._draw();

    // input type=number does not support the 'pattern' attribute, so
    // neither should ojInputNumber.
    // remove this before EditableValue grabs it and uses it.
    node.removeAttr("pattern");

    this._inputNumberDefaultValidators = {};
    this._setup();
    // I want everything set up before I turn on events, since the events affect the component,
    // like keydown will update the value and update the buttons.
    this._on(this._events);
  },
    /**
   * Performs post processing after _SetOption() is called. Different options when changed perform
   * different tasks. See _AfterSetOption[OptionName] method for details.
   * 
   * @param {string} option
   * @param {Object|string=} previous
   * @param {Object=} flags 
   * @protected
   * @memberof! oj.ojInputNumber
   * @instance
   */
  _AfterSetOption : function (option, previous, flags)
  {
    this._superApply(arguments);
    switch (option)
    {
      case "min": 
      case "max":
        this._Refresh(option, this.options[option]);
        break; 
      default:
        break;
    }
    
  },
  
  /**
   * Handles options specific to inputnumber.
   * Note that _setOption does not get called during create in the super class. 
   * It only gets called when the component has already been created.
   * However, we do call _setOption in _draw for certain attributes 
   * (disabled)
   * @override
   * @protected
   * @memberof oj.ojInputNumber
   */
  _setOption: function(key, value, flags)
  {
    var coercedValue;

    if (key === "value" || key === "max" || key === "min")
    {
      coercedValue = this._parse(key, value);
    }
    else if (key === "step")
    {
      coercedValue = this._parseStep(value);    
    }
    else
      coercedValue = value;
    

    // the superclass calls _Refresh. Our _Refresh calls _updateButtons
    // and _refreshAriaMinMaxValue.
    // call _super with the newly coerced 'value' property.
    this._super(key, coercedValue, flags);
    
    if (key === "max" || key === "min")
    {
      // since validators are immutable, they will contain min + max as local values. 
      // Because of this will need to recreate
      this._createRangeValidator();
      this._AfterSetOptionValidators();
    }

    // when a dom element supports disabled, use that, and not aria-disabled.
    // having both is an error. 
    // having aria-disabled on root dom element is ok (if it is added in base class)
    if (key === "disabled")
    {
      // force it to be a boolean. this is what/how ojbutton, EditableValue does.
      this.element.prop("disabled", !!value);
    }
    // when a dom element supports readonly, use that, and not aria-readonly.
    // having both is an error
    if (key === "readOnly")
    {
      this.element.prop("readonly", !!value);
      this._refreshStateTheming("readOnly", this.options.readOnly);
      this._refreshRoleSpinbutton("readOnly", this.options.readOnly);
    }
  },
  /**
   * Override of protected base class method.  
   * Method name needn't be quoted since is in externs.js.
   * @protected
   * @memberof oj.ojInputNumber
   * @instance
   */
  _destroy: function()
  {
    var ret = this._super();

    // destroy the buttons
    this.upButton.ojButton("destroy");
    this.downButton.ojButton("destroy");
    this.upButton.remove();
    this.downButton.remove();
    this.upButton = null;
    this.downButton = null;

    // Bug #19639907 - DomUtils.unwrap() will avoid unwrapping if the node is being destroyed by Knockout
    oj.DomUtils.unwrap(this.element, this.uiInputNumber);
    clearTimeout(this.timer);
    return ret;
  },
  /**
   * Used for explicit cases where the component needs to be refreshed 
   * (e.g., when the value option changes or other UI gestures).
   * @override
   * @protected
   * @memberof oj.ojInputNumber
   */
  _Refresh: function(name, value, forceDisplayValueRefresh)
  {
    this._superApply(arguments);
    var valueMinMax = (name === "value" || name === "max" || name === "min");
    var valueMinMaxDisabled = valueMinMax || name === "disabled"; 
    var valuenow;
    
    if (valueMinMaxDisabled)
    {
      valuenow = this._getConvertedDisplayValue();
    }
    if (valueMinMax)
      this._refreshAriaMinMaxValue(valuenow);
    // needs to get called if value, min, max, or disabled change, but not otherwise.
    // put this condition since EditableValue calls _Refresh for every
    // option change, and we don't want to updateButtons for every single option
    // change.
    if (valueMinMaxDisabled)
      this._updateButtons(valuenow);
  },
  // *********** END WIDGET FACTORY METHODS **********
  /**
   * Need to override since we allow users to set the converter to null, undefined, and etc and when 
   * they do we use the default converter
   * 
   * @return {Object} a converter instance or null
   * 
   * @memberof oj.ojInputNumber
   * @instance
   * @protected
   * @override
   */
  _GetConverter : function () 
  {
    return this.options['converter'] ? 
        this._superApply(arguments) : 
        $["oj"]["ojInputNumber"]["prototype"]["options"]["converter"];
  },
  /**
   * Sets up the default numberRange validators if there is a min or max.
   * 
   * @ignore
   * @protected
   * @override
   * @instance
   * @memberof oj.ojInputNumber
   */
  _GetImplicitValidators: function()
  {
    var ret = this._superApply(arguments);
    if (this.options['min'] != null || this.options['max'] != null)
    {
      this._createRangeValidator();
    }

    return $.extend(this._inputNumberDefaultValidators, ret);
  },
  /**
   * Returns the default styleclass for the component.
   * 
   * @return {string}
   * @memberof oj.ojInputNumber
   * @override
   * @protected
   */
  _GetDefaultStyleClass: function()
  {
    return "oj-inputnumber";
  },
  _events:
  {
    'input': function(event)
    {
      this._SetRawValue(event, this.element.val());
    },
    'keydown': function(event)
    {
      var keyCode = $.ui.keyCode;
      if (event.keyCode === keyCode.ENTER)
      {
        this._blurEnterSetValue(event);
        event.preventDefault();
      }
      else if (this._start() && this._keydown(event))
      {
        event.preventDefault();
      }
    },
    'keyup': function(event) 
    {
      this._stop(event);
    },
    'focus': function()
    {
      this.previous = this.element.val();
    },
    'blur': function(event)
    {
      if (this.cancelBlur)
      {
        delete this.cancelBlur;
        return;
      }
      this._blurEnterSetValue(event);
    },
    "mousedown .oj-inputnumber-button": function(event)
    {
      var previous;

      // We never want the buttons to have focus; whenever the user is
      // interacting with the inputnumber, the focus should be on the input.
      // If the input is focused then this.previous is properly set from
      // when the input first received focus. If the input is not focused
      // then we need to set this.previous based on the value before spinning.
      previous = this.element[0] === this.document[0].activeElement ?
              this.previous : this.element.val();

      function checkFocus()
      {
        var isActive = this.element[0] === this.document[0].activeElement;
        if (!isActive)
        {
          this.element.focus();
          this.previous = previous;
          // support: IE
          // IE sets focus asynchronously, so we need to check if focus
          // moved off of the input because the user clicked on the button.
          this._delay(function()
          {
            this.previous = previous;
          });
        }
      }

      // ensure focus is on (or stays on) the text field
      event.preventDefault();
      checkFocus.call(this);

      // support: IE
      // IE doesn't prevent moving focus even with event.preventDefault()
      // so we set a flag to know when we should ignore the blur event
      // and check (again) if focus moved off of the input.
      this.cancelBlur = true;
      this._delay(function()
      {
        delete this.cancelBlur;
        checkFocus.call(this);
      });

      this._start();

      this._repeat(null, $(event.currentTarget).hasClass("oj-inputnumber-up") ? 1 : -1, event);
    },
    "mouseup .oj-inputnumber-button": function(event)
    {
      this._stop(event);
    },
    "mouseenter .oj-inputnumber-button": function(event)
    {
      // button will add oj-active if mouse was down while mouseleave and kept down
      if (!$(event.currentTarget).hasClass("oj-active"))
      {
        return;
      }

      this._start();

      this._repeat(null, $(event.currentTarget).hasClass("oj-inputnumber-up") ? 1 : -1, event);
    },
    // TODO: do we really want to consider this a stop?
    // shouldn't we just stop the repeater and wait until mouseup before
    // we trigger the stop event?
    "mouseleave .oj-inputnumber-button": function(event)
    {
      this._stop(event);
    }
  },
  // I N T E R N A L   P R I V A T E   C O N S T A N T S    A N D   M E T H O D S 
  // Subclasses should not override or call these methods
  /**
   * @private
   * @const
   */
  _BUNDLE_KEY:
  {
    _TOOLTIP_DECREMENT: 'tooltipDecrement',
    _TOOLTIP_INCREMENT: 'tooltipIncrement'
  },
  /**
   * when below listed options are passed to the component, corresponding CSS will be toggled
   * @private
   * @const
   * @type {Object}
   */
  _OPTION_TO_CSS_MAPPING: 
  {
    "readOnly": "oj-read-only"
  },
    /**
   * _setup is called on create and refresh.
   * @private
   */
  _setup: function() 
  {

    // add/update translated strings to buttons
    var incrementString =
            this.getTranslatedString(this._BUNDLE_KEY._TOOLTIP_INCREMENT);
    var decrementString =
            this.getTranslatedString(this._BUNDLE_KEY._TOOLTIP_DECREMENT);
    var valuenow = this._getConvertedDisplayValue();
    this.upButton.ojButton({label: incrementString});
    this.downButton.ojButton({label: decrementString});
    this._refreshAriaMinMaxValue(valuenow);
    this._updateButtons(valuenow);
    // update element DOM for readOnly
    if (typeof this.options['readOnly'] === "boolean")
    {
      this.element.prop("readonly", this.options['readOnly']);
    }
    this._refreshStateTheming("readOnly", this.options.readOnly);
    this._refreshRoleSpinbutton("readOnly", this.options.readOnly);
  }, 
  _createOjButton: function()
  {
    this.upButton = this.uiInputNumber.find(".oj-inputnumber-up").ojButton({display: 'icons',
      icons: {start: 'oj-component-icon oj-inputnumber-up-icon'}});
    this.downButton = this.uiInputNumber.find(".oj-inputnumber-down").ojButton({display: 'icons',
      icons: {start: 'oj-component-icon oj-inputnumber-down-icon'}});
  },
  /**
   * @private
   */
  _draw: function()
  {
    var element = this.element;
    var uiInputNumber = this.uiInputNumber = element.addClass("oj-inputnumber-input")
            // @HTMLUpdateOK
            .wrap(this._uiInputNumberHtml()).parent()
            // add buttons
            // @HTMLUpdateOK
            .append(this._buttonHtml())
            // @HTMLUpdateOK
            .wrap("<div class='oj-inputnumber oj-component'></div>").parent();

    // 
    // TODO: need to save off attributes and reset on destroy generically.
    this.saveType = element.prop("type");
    element.attr("type", "text");


    // add aria-hidden=true to buttons. As they are not in the keyboard sequence 
    // we decided it makes more sense to just add aria-hidden="true" to them 
    // and rely on the up/down arrow keys
    uiInputNumber.find(".oj-inputnumber-button")
            .attr("tabIndex", "-1").attr("aria-hidden", true);
    this._createOjButton();
  },
  /**
   * @private
   */
  _keydown: function(event)
  {
    var keyCode = $.ui.keyCode;

    switch (event.keyCode)
    {
      // keeping the up/down pressed repeats
      // using the up and down arrows will adjust the value so that it is 
      // a multiple of step and it is in min/max, same as if you used the 
      // up and down buttons
      case keyCode.UP:
        this._repeat(null, 1, event);
        return true;
      case keyCode.DOWN:
        this._repeat(null, -1, event);
        return true;
    }

    return false;
  },
  /**
   * @private
   */
  _uiInputNumberHtml: function()
  {
    // need to wrap the input+buttons with a span so that inline messaging
    // can come after this span, and we can position popups on this span.
    return "<span class='oj-inputnumber-wrapper'></span>";
  },
  /**
   * @private
   */
  _buttonHtml: function()
  {
    return "" + "<a class='oj-inputnumber-button oj-inputnumber-down'></a>" +
            "<a class='oj-inputnumber-button oj-inputnumber-up'></a>";
  },
  /**
   * @private
   */
  _start: function()
  {
    this.spinning = true;
    return true;
  },
  /**
   * @private
   */
  _repeat: function(i, steps, event)
  {
    // repeat spinning as long as the key is down and min/max isn't reached
    i = i || 500;

    clearTimeout(this.timer);
    this.timer = this._delay(function()
    {
      this._repeat(40, steps, event);
    },
            i);

    this._spin(steps * this.options.step, event);
  },
  /**
   * @private
   * @param {Number} step - Number of steps to increment.
   * @param {Object=} event an optional event if this was a result of ui interaction.
   */
  _spin: function(step, event)
  {
    // When the component's 'value' changes, the displayValue is automatically updated.
    // So reading the component's display value should always give you the element's value
    var value = this._getConvertedDisplayValue();
    value = this._adjustValue(value, step);

    this._SetValue(value, event, this._VALIDATION_MODE.VALIDATORS_ONLY);
  },
  /**
   * called from _adjustValue
   * @private
   */
  _precision: function()
  {
    var opts = this.options, minOpt = opts.min;
    var precision = this._precisionOf(opts.step);
    if (minOpt != null)
    {
      precision = Math.max(precision, this._precisionOf(minOpt));
    }
    return precision;
  },
  /**
   * return the number of digits after the '.'
   * called from _adjustValue->_precision
   * @private
   * @param {Number} num - Number from which to calculate the precision
   */
  _precisionOf: function(num)
  {
    var str = num.toString(), decimal = str.indexOf(".");
    return decimal === -1 ? 0 : str.length - decimal - 1;
  },
  /**
   * adjust the value to be "valid".
   * The logic follows that of HTML-5's input number.
   * http://www.w3.org/TR/html5/forms.html#dom-input-stepup
   * A valid value is one that is a multiple of 
   * step starting at stepBase, where stepBase is min (if present),
   * else initial value (if present) TODO,
   * else (if type == number) 0 
   * If max is not a valid value, stepUp/stepDown will never go to max. It
   * will go to the calculated valid max (one that is the largest value 
   * that is an integral multiple of the step, and that is less than or equal
   * to the maximum.
   * @private
   */
  _adjustValue: function(value, step)
  {
    var newValue;
    var stepBase, aboveMin, options = this.options, 
            minOpt = options.min, stepOpt = options.step, maxOpt = options.max;
    var precision = this._precision();

    // make sure we're at a valid step when we step up or down.
    // - find out where we are relative to the base (min or 0)
    stepBase = minOpt != null ? minOpt : 0;

    // From http://www.w3.org/TR/html5/forms.html#dom-input-stepup:
    // If value subtracted from the step base is not an integral multiple 
    // of the step, then set value to the nearest value that, when subtracted
    // from the step base, is an integral multiple of the allowed value step,
    // and that is less than value if the method invoked was stepDown() and
    // more than value if the method invoked was stepUp().

    // is value-stepBase an integral multiple of step?
    aboveMin = value - stepBase;
    var rounded = Math.round(aboveMin / stepOpt) * stepOpt;
    rounded = parseFloat(rounded.toFixed(precision));
    var multiple = (rounded === aboveMin);

    if (!multiple)
    {
      if (step < 0)
        aboveMin = Math.ceil(aboveMin / stepOpt) * stepOpt;
      else
      {
        aboveMin = Math.floor(aboveMin / stepOpt) * stepOpt;
      }

      // rounding is based on 0, so adjust back to our base
      newValue = stepBase + aboveMin + step;
    }
    else
    {
      newValue = value + step;
    }

    // fix precision from bad JS floating point math
    // toFixed returns the newValue with a specific # of digits after the 
    // decimal point (this_precision() looks at max of step/min's # of 
    // digits.
    newValue = parseFloat(newValue.toFixed(precision));

    if (minOpt != null && newValue < minOpt)
      return minOpt;

    if (maxOpt!= null && newValue > maxOpt)
    {
      var validMax = (Math.floor((maxOpt - stepBase) / stepOpt) *
              stepOpt) + stepBase;
      // fix precision from bad JS floating point math
      validMax = parseFloat(validMax.toFixed(precision));
      return validMax;
    }

    return newValue;
  },
  /**
   * @private
   */
  _stop: function(event)
  {
    if (!this.spinning)
    {
      return;
    }
    clearTimeout(this.timer);
    this.spinning = false;
  },
  /**
   * disables or enables both the up and down buttons depending upon what the value
   * is on the screen after conversion plus what min/max are set to. 
   * e.g., $10.00 is on the screen, valuenow is 10
   * TODO: double check if I can use the value option instead of doing it this way.
   * @private
   */
  _updateButtons: function(valuenow)
  {
    var options = this.options, minOpt = options.min, maxOpt = options.max;
    if (!this.uiInputNumber)
      return;
    var downButton = this.downButton;
    var upButton = this.upButton;

    if (options.disabled || valuenow === undefined)
    {
      downButton.ojButton("disable");
      upButton.ojButton("disable");
    }
    else if (maxOpt != null && valuenow >= maxOpt)
    {
      downButton.ojButton("enable");
      upButton.ojButton("disable");
    }
    else if (minOpt != null && valuenow <= minOpt)
    {
      downButton.ojButton("disable");
      upButton.ojButton("enable");
    }
    else
    {
      downButton.ojButton("enable");
      upButton.ojButton("enable");
    }

  },
  /**
   * Returns the converted display value. 
   * This function gets the display value (or 0 if no display value), then parses it using
   * the converter.
   * The converted display value is used for 'valuenow'. For example, 
   * the display value might be $6.00, but we want valuenow to be 6.
   * @private
   */
  _getConvertedDisplayValue: function()
  {
    var value, displayValue;
    try
    {
      displayValue = this._GetDisplayValue() || 0;
      // if displayValue is not parseable, say it is 'abc', 
      // then _parseValue throws an error. catch it and move on.
      // TODO: Make _parseValue protected in EditableValue();
      value = this._parseValue(displayValue);
    }
    catch (e)
    {
      // catch the error, set value to undefined, and continue to update
      // the buttons. both the up/down buttons will be disabled in this case.
      value = undefined;
    }
    return value;
  },
  /**
   * @private
   */
  _blurEnterSetValue: function(event)
  {
    var val = this.element.val();
    this._stop();  
    var valuenow = this._getConvertedDisplayValue();
    this._refreshAriaMinMaxValue(valuenow);
    this._updateButtons(valuenow);
    // _SetValue triggers valuechange event
    this._SetValue(val, event);
  },
  /**
   * @private
   */
  _createRangeValidator: function()
  {
    var options = this.options, minOpt = options.min, maxOpt = options.max;
    var newMin = minOpt != null ? minOpt : undefined;
    var newMax = maxOpt != null ? maxOpt : undefined;
    var translations = options.translations;
    
    var reqTrans = translations ? translations['numberRange'] || {}: {};

    var hintMin, hintMax, hintInRange;
    var messageDetailRangeOverflow, messageDetailRangeUnderflow;
    var messageSummaryRangeOverflow, messageSummaryRangeUnderflow;

    var hint = reqTrans['hint'] || {};
    var messageDetail = reqTrans['messageDetail'] || {};
    var messageSummary = reqTrans['messageSummary'] || {};

    if (hint !== null)
    {
      hintMin = hint['min'] || null;
      hintMax = hint['max'] || null;
      hintInRange = hint['inRange'] || null;
    }
    if (messageDetail !== null)
    {
      messageDetailRangeOverflow = messageDetail['rangeOverflow'] || null;
      messageDetailRangeUnderflow = messageDetail['rangeUnderflow'] || null;
    }
    if (messageSummary !== null)
    {
      messageSummaryRangeOverflow = messageSummary['rangeOverflow'] || null;
      messageSummaryRangeUnderflow = messageSummary['rangeUnderflow'] || null;
    }

    var numberRangeOptions = {
      'min': newMin,
      'max': newMax,
      'hint' : {'min':hintMin || null,
                'max':hintMax || null,
                'inRange': hintInRange || null
               },
      'messageDetail' : {
                'rangeOverflow':messageDetailRangeOverflow || null, 
                'rangeUnderflow': messageDetailRangeUnderflow || null},
      'messageSummary' : {
                'rangeOverflow':messageSummaryRangeOverflow || null, 
                'rangeUnderflow': messageSummaryRangeUnderflow || null},
      'converter': this._GetConverter()};
     
    this._inputNumberDefaultValidators[oj.ValidatorFactory.VALIDATOR_TYPE_NUMBERRANGE] =
            oj.Validation.validatorFactory(oj.ValidatorFactory.VALIDATOR_TYPE_NUMBERRANGE)
            .createValidator(numberRangeOptions);
  },

  // The user can clear out min/max by setting the option to null, so we
  // do not coerce null.
  /**
   * @param {string} option name of the option. this will show up in the error if thrown
   * @param val value to parse
   * @throws {Error} if option value is invalid
   * @private
   */
  _parse: function(option, val)
  {
    var returnValue;
    if (val !== null)
      returnValue = +val;
    else
      returnValue = val;

    // isNaN(null) returns false, which is what we want
    if (isNaN(returnValue))
      throw new Error("ojInputNumber's " + option + " option is not a number");
   
    return returnValue;
  },
  /**
   * parse the step's value
   * We are following the behavior of HTML-5 the best we can. According
   * to the spec, it says step must be a number greater than 0. 
   * Chrome defaults it to 1 if it is not.
   * @throws {Error} if option value is invalid 
   * @private
   */
  _parseStep: function(val)
  {
    var defaultStep = 1, parsedStep;
    if (val === null)
      return defaultStep;
    parsedStep = this._parse("step", val);
    if (parsedStep <= 0)
    {
      // throw an exception
      throw new Error("Invalid step for ojInputNumber; step must be > 0");
    }
    // DEFAULT to 1 if it isn't > 0
    if (parsedStep === null || parsedStep <= 0)
      parsedStep = defaultStep;
    return parsedStep;
  },
  /**
   * Toggles css selector on the widget. E.g., when readOnly option changes, 
   * the oj-read-only selector needs to be toggled.
   * @param {string} option
   * @param {Object|string|boolean} value 
   * @private
   */
  _refreshStateTheming: function(option, value)
  {
    if (Object.keys(this._OPTION_TO_CSS_MAPPING).indexOf(option) != -1)
    {
      // value is a boolean
      this.widget().toggleClass(this._OPTION_TO_CSS_MAPPING[option], !!value);
    }
  },
  /**
   * When readOnly option changes, 
   * the role spinbutton needs to be toggled We don't have role spinbutton
   * on readOnly inputNumber.
   * @param {string} option
   * @param {Object|string|boolean} readOnly 
   * @private
   */
  _refreshRoleSpinbutton: function(option, readOnly)
  {
    readOnly = !!readOnly;
    // if readonly is true, remove role spinbutton
    // if readonly is false, add role spinbutton
    if (readOnly)
      this.element.removeAttr("role");
    else
      this.element.attr("role", "spinbutton");
  },
  /* updates the aria-value information */
  _refreshAriaMinMaxValue: function(valuenow)
  {
    var element = this.element;
    var valuetext = element.val();

    element.attr(
            {
              "aria-valuemin": this.options.min, "aria-valuemax": this.options.max,
              // TODO: what should we do with values that can't be parsed?
              // TODO: Ask Pavitra, do we need to parse the value?
              "aria-valuenow": valuenow
            });
    if (!this._CompareOptionValues("value", "" + valuenow, valuetext))
      element.attr({"aria-valuetext": valuetext});
  },
  /**
   * step the inputnumber value up or down
   * @private
   * @param {Number} steps - Number of steps to increment.
   * @param {boolean} up If true step up, else step down.
   */
  _step: function(steps, up)
  {
    this._start();
    if (up)
      this._spin((steps || 1) * this.options.step);
    else
      this._spin((steps || 1) * -this.options.step);
    this._stop();
  }
  
  // API doc for inherited methods with no JS in this file:
  
  /**
   * Removes the inputNumber functionality completely. 
   * This will return the element back to its pre-init state.
   * 
   * <p>This method does not accept any arguments.
   * 
   * @method
   * @name oj.ojInputNumber#destroy
   * @memberof oj.ojInputNumber
   * @instance
   * 
   * @example <caption>Invoke the <code class="prettyprint">destroy</code> method:</caption>
   * $( ".selector" ).ojInputNumber( "destroy" );
   */
  
      // Fragments:

    /**
     * <table class="keyboard-table">
     *   <thead>
     *     <tr>
     *       <th>Target</th>
     *       <th>Gesture</th>
     *       <th>Action</th>
     *     </tr>
     *   </thead>
     *   <tbody>
     *     <tr>
     *       <td>Up Button</td>
     *       <td><kbd>Tap</kbd></td>
     *       <td>Increment the number.</td>
     *     </tr>
     *     <tr>
     *       <td>Down Button</td>
     *       <td><kbd>Tap</kbd></td>
     *       <td>Decrement the number.</td>
     *     </tr>
     *     <tr>
     *       <td>Input</td>
     *       <td><kbd>Tap</kbd></td>
     *       <td>Set focus to the input. If hints, title or messages exists in a notewindow, 
     *       pop up the notewindow.</td>
     *     </tr>
     *     <tr>
     *       <td>Elsewhere on Page</td>
     *       <td><kbd>Touch</kbd></td>
     *       <td>Submit the value you typed in the input field.</td>
     *     </tr>
     *     {@ojinclude "name":"labelTouchDoc"}     
     *   </tbody>
     * </table>
     *
     * 
     * @ojfragment touchDoc - Used in touch gesture section of classdesc, and standalone gesture doc
     * @memberof oj.ojInputNumber
     */
        
    /**
     * <table class="keyboard-table">
     *   <thead>
     *     <tr>
     *       <th>Target</th>
     *       <th>Key</th>
     *       <th>Action</th>
     *     </tr>
     *   </thead>
     *   <tbody>
     *     <tr>
     *       <td rowspan="3">Input</td>
     *       <td><kbd>Enter</kbd> or <kbd>Tab</kbd></td>
     *       <td>Submit the value you typed in the input field.</td>
     *     </tr>
     *     <tr>
     *       <td><kbd>UpArrow</kbd></td>
     *       <td>Increment the number.</td>
     *     </tr>
     *     <tr>
     *       <td><kbd>DownArrow</kbd></td>
     *       <td>Decrement the number.</td>
     *     </tr>
     *     <tr>
     *       <td>Tabbable element immediately before inputNumber</td>
     *       <td><kbd>Tab</kbd></td>
     *       <td>Set focus to input. If hints, title or messages exist in a notewindow, 
     *       pop up the notewindow.</td>
     *     </tr>
     *     {@ojinclude "name":"labelKeyboardDoc"} 
     *   </tbody>
     * </table>
     *
     *
     * @ojfragment keyboardDoc - Used in keyboard section of classdesc, and standalone gesture doc
     * @memberof oj.ojInputNumber
     */
    
});

//////////////////     SUB-IDS     //////////////////

  /**
 * <p>Sub-ID for the inputNumber's Up arrow.
 * 
 * <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and 
 * <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
 * 
 * @ojsubid
 * @member
 * @name oj-inputnumber-up
 * @memberof oj.ojInputNumber
 * @instance
 * 
 * @example <caption>Get the node for the Up arrow:</caption>
 * var node = $( ".selector" ).ojInputNumber( "getNodeBySubId", {'subId': 'oj-inputnumber-up'} );
 */

/**
 * <p>Sub-ID for the inputNumber's Down arrow.
 * 
 * <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and 
 * <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
 * 
 * @ojsubid
 * @member
 * @name oj-inputnumber-down
 * @memberof oj.ojInputNumber
 * @instance
 * 
 * @example <caption>Get the node for the Down arrow:</caption>
 * var node = $( ".selector" ).ojInputNumber( "getNodeBySubId", {'subId': 'oj-inputnumber-down'} );
 */

/**
 * <p>Sub-ID for the inputNumber's input element.
 * 
 * <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and 
 * <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
 * 
 * @ojsubid
 * @member
 * @name oj-inputnumber-input
 * @memberof oj.ojInputNumber
 * @instance
 * 
 * @example <caption>Get the node for the input element:</caption>
 * var node = $( ".selector" ).ojInputNumber( "getNodeBySubId", {'subId': 'oj-inputnumber-input'} );
 */