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

Oracle® JavaScript Extension Toolkit (JET)
1.1.2

E65298-01

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

/**
 * @ojcomponent oj.ojInputDateTime
 * @augments oj.ojInputDate
 * @since 0.6
 * 
 * @classdesc
 * <h3 id="inputDateTimeOverview-section">
 *   JET ojInputDateTime Component
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#inputDateTimeOverview-section"></a>
 * </h3>
 * 
 * <p>Description: ojInputDateTime extends from ojInputDate providing additionally time selection drop down. Please note that for V1 timezone is not supported 
 * by the converter; hence not by the component.</p>
 * <h3 id="keyboard-section">
 *   Keyboard End User Information
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#keyboard-section"></a>
 * </h3>
 * 
 * <p>
 * 
 * <table class="keyboard-table">
 *   <thead>
 *     <tr>
 *       <th>Key</th>
 *       <th>Use</th>
 *     </tr>
 *   </thead>
 *   <tbody>
 *     <tr>
 *       <td><kbd>Enter</kbd></td>
 *       <td>Select the currently focused day</td>
 *     </tr>
 *     <tr>
 *       <td><kbd>UpArrow</kbd></td>
 *       <td>Move up in the grid.</tr>
 *     <tr>
 *       <td><kbd>DownArrow</kbd></td>
 *       <td>Move down in the grid.</tr>
 *     <tr>
 *       <td><kbd>RightArrow</kbd></td>
 *       <td>Move right in the grid.</tr>
 *     <tr>
 *       <td><kbd>LeftArrow</kbd></td>
 *       <td>Move left in the grid.</tr>
 *     <tr>
 *       <td><kbd>Esc</kbd></td>
 *       <td>Close the grid.</tr>
 *     <tr>
 *       <td><kbd>Home</kbd></td>
 *       <td>Move focus to first day of the month.</tr>
 *     <tr>
 *       <td><kbd>End</kbd></td>
 *       <td>Move focus to last day of the month.</tr>
 *     <tr>
 *       <td><kbd>PageUp</kbd></td>
 *       <td>Switch to previous month.</tr>
 *     <tr>
 *       <td><kbd>PageDown</kbd></td>
 *       <td>Switch to next month.</tr>
 *     <tr>
 *       <td><kbd>Alt + PageUp</kbd></td>
 *       <td>Switch to previous year.</tr>
 *     <tr>
 *       <td><kbd>Alt + PageDown</kbd></td>
 *       <td>Switch to next year.</tr>
 *     <tr>
 *       <td><kbd>Ctrl + Alt + PageUp</kbd></td>
 *       <td>Switch to previous by stepBigMonths.</tr>
 *     <tr>
 *       <td><kbd>Ctrl + Alt + PageDown</kbd></td>
 *       <td>Switch to next by stepBigMonths.</tr>
 *     <tr>
 *       <td><kbd>Ctrl + Alt + T</kbd></td>
 *       <td>Places focus on Today button if it exists.</tr>
 *     <tr>
 *       <td><kbd>Shift + DownArrow or UpArrow</kbd></td>
 *       <td>Shows the timepicker and moves the focus into the expanded timepicker list</td>
 *     </tr>
 * </tbody></table>
 * 
 * <h3 id="pseudos-section">
 *   Pseudo-selectors
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#pseudos-section"></a>
 * </h3>
 * 
 * <pre class="prettyprint">
 * <code>$( ":oj-inputDateTime" )            // selects all JET input on the page
 * </code>
 * </pre>
 * 
  * <h3 id="a11y-section">
 *   Accessibility
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#a11y-section"></a>
 * </h3>
 * <p>
 * It is up to the application developer to associate the label to the input component.
 * For inputDateTime, you should put an <code>id</code> on the input, and then set 
 * the <code>for</code> attribute on the label to be the input's id.
 * </p>
 * <h3 id="label-section">
 *   Label and InputDateTime
 *   <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>id</code> on the input, and then setting the 
 * <code>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>required</code> and <code>help</code> options are set. 
 * </p> 
 * <h3 id="binding-section">
 *   Declarative Binding
 *   <a class="bookmarkable-link" title="Bookmarkable Link" href="#binding-section"></a>
 * </h3>
 * 
 * <pre class="prettyprint">
 * <code>
 *    <input id="dateTimeId" data-bind="ojComponent: {component: 'ojInputDateTime'}" />
 * </code>
 * </pre>
 * 
 * @desc Creates or re-initializes a JET ojInputDateTime
 * 
 * @param {Object=} options a map of option-value pairs to set on the component
 * 
 * @example <caption>Initialize the input element with no options specified:</caption>
 * $( ".selector" ).ojInputDateTime();
 * 
 * * @example <caption>Initialize the input element with some options:</caption>
 * $( ".selector" ).ojInputDateTime( { "disabled": true } );
 * 
 * @example <caption>Initialize the input element via the JET <code class="prettyprint">ojComponent</code> binding:</caption>
 * <input id="dateTimeId" data-bind="ojComponent: {component: 'ojInputDateTime'}" />
 */
oj.__registerWidget("oj.ojInputDateTime", $['oj']['ojInputDate'], 
{
  version : "1.0.0", 
  widgetEventPrefix : "oj",
  
  //-------------------------------------From base---------------------------------------------------//
  _WIDGET_CLASS_NAMES : "oj-inputdatetime-date-time oj-component oj-inputdatetime",
  _INPUT_HELPER_KEY: "inputHelpBoth",
  //-------------------------------------End from base-----------------------------------------------//
  
  options : 
  {
    /**
     * Default converter for ojInputDateTime
     *
     * If one wishes to provide a custom converter for the ojInputDateTime override the factory returned for
     * oj.Validation.converterFactory(oj.ConverterFactory.CONVERTER_TYPE_DATETIME)
     *
     * @expose
     * @instance
     * @memberof! oj.ojInputDateTime
     * @default <code class="prettyprint">oj.Validation.converterFactory(oj.ConverterFactory.CONVERTER_TYPE_DATETIME).createConverter({"day": "2-digit", "month": "2-digit", "year": "2-digit", "hour": "2-digit", "hour12": true, "minute": "2-digit"})</code>
     */
    converter : oj.Validation.converterFactory(oj.ConverterFactory.CONVERTER_TYPE_DATETIME).createConverter(
    {
      "day" : "2-digit", "month" : "2-digit", "year" : "2-digit", "hour" : "2-digit", "hour12" : true, "minute" : "2-digit"
    }),
    
    /**
     * Time Picker option is a JSON object containing sub-options for the ojInputDateTime component
     * 
     * <p>
     * The properties supported on the timePicker option are:
     * @property {string=} timeIncrement Time increment to be used for ojInputDateTime, the format is hh:mm:ss:SS. <br/> 
     * The default value is <code class="prettyprint">{timePicker: {timeIncrement': "00:30:00:00"}}</code>. <br/>
     * Example <code class="prettyprint">$(".selector").ojInputDateTime("option", "timePicker.timeIncrement", "00:10:00:00");</code>
     * </p>
     * 
     * @expose
     * @instance
     * @memberof! oj.ojInputDateTime
     * @type {Object.<string>}
     */
    timePicker: 
    {
      /**
       * @expose
       */
      timeIncrement : "00:30:00:00"
    }
    
    /**
     * The maximum selectable datetime. When set to null, there is no maximum.
     *
     * <ul>
     *  <li> type string - local ISOString meaning lacking Z, timezone, and timezone offset
     *  <li> null - no limit
     * </ul>
     * 
     * @example <caption>Initialize the component with the <code class="prettyprint">max</code> option:</caption>
     * <input id="date" data-bind="ojComponent: {component: 'ojInputDateTime', max: '2014-09-25T13:30:00.000'}" />
     * 
     * @expose
     * @name max
     * @instance
     * @memberof! oj.ojInputDateTime
     * @default <code class="prettyprint">null</code>
     */
    
    /**
     * The minimum selectable date. When set to null, there is no minimum.
     *
     * <ul>
     *  <li> type string - local ISOString meaning lacking Z, timezone, and timezone offset
     *  <li> null - no limit
     * </ul>
     * 
     * @example <caption>Initialize the component with the <code class="prettyprint">min</code> option:</caption>
     * <input id="date" data-bind="ojComponent: {component: 'ojInputDateTime', min: '2014-08-25T08:00:00.000'}" />
     * 
     * @expose
     * @name min
     * @instance
     * @memberof! oj.ojInputDateTime
     * @default <code class="prettyprint">null</code>
     */
    
    /** 
     * List of validators used by component when performing validation. Each item is either an 
     * instance that duck types {@link oj.Validator}, or is an Object literal containing the 
     * properties listed below. Implicit validators created by a component when certain options 
     * are present (e.g. <code class="prettyprint">required</code> option), are separate from 
     * validators specified through this option. At runtime when the component runs validation, it 
     * combines the implicit validators with the list specified through this option. 
     * <p>
     * Hints exposed by validators are shown in the notewindow by default, or as determined by the 
     * 'validatorHint' property set on the <code class="prettyprint">displayOptions</code> 
     * option. 
     * </p>
     * 
     * <p>
     * When <code class="prettyprint">validators</code> option changes due to programmatic 
     * intervention, the component may decide to clear messages and run validation, based on the 
     * current state it is in. </br>
     * 
     * <h4>Steps Performed Always</h4>
     * <ul>
     * <li>The cached list of validator instances are cleared and new validator hints 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 validators changes, component does nothing other than the 
     * steps it always performs.</li>
     * <li>if component is invalid and is showing messages -
     * <code class="prettyprint">messagesShown</code> option is non-empty, when 
     * <code class="prettyprint">validators</code> changes then all component messages are cleared 
     * and full validation run using the display value on the component. 
     * <ul>
     *   <li>if there are validation errors, then <code class="prettyprint">value</code> 
     *   option is not updated and the error pushed to <code class="prettyprint">messagesShown</code>
     *   option. 
     *   </li>
     *   <li>if no errors result from the validation, the <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.</li>
     * </ul>
     * </li>
     * <li>if component is invalid and has deferred messages when validators changes, it does 
     * nothing other than the steps it performs always.</li>
     * </ul>
     * </p>
     * 
     * <h4>Clearing Messages</h4>
     * <ul>
     * <li>Only messages created by the component are cleared.  These include ones in 
     * <code class="prettyprint">messagesHidden</code> and <code class="prettyprint">messagesShown</code>
     *  options.</li>
     * <li><code class="prettyprint">messagesCustom</code> option is not cleared.</li>
     * </ul>
     * </p>
     * 
     * @property {string} type - the validator type that has a {@link oj.ValidatorFactory} that can 
     * be retrieved using the {@link oj.Validation} module. For a list of supported validators refer 
     * to {@link oj.ValidatorFactory}. <br/>
     * @property {Object=} options - optional Object literal of options that the validator expects. 
     * 
     * @example <caption>Initialize the component with validator object literal:</caption>
     * $(".selector").ojInputDateTime({
     *   validators: [{
     *     type: 'dateTimeRange', 
     *     options : {
     *       max: '2014-09-10T13:30:00.000',
     *       min: '2014-09-01T00:00:00.000'
     *     }
     *   }],
     * });
     * 
     * NOTE: oj.Validation.validatorFactory('dateTimeRange') returns the validator factory that is used 
     * to instantiate a range validator for dateTime.
     * 
     * @example <caption>Initialize the component with multiple validator instances:</caption>
     * var validator1 = new MyCustomValidator({'foo': 'A'}); 
     * var validator2 = new MyCustomValidator({'foo': 'B'});
     * // Foo is InputText, InputNumber, Select, etc.
     * $(".selector").ojFoo({
     *   value: 10, 
     *   validators: [validator1, validator2]
     * });
     * 
     * @expose 
     * @name validators
     * @instance
     * @memberof oj.ojInputDateTime
     * @type {Array|undefined}
     */
    
    /** 
     * The value of the ojInputDateTime component which should be a local ISOString meaning lacking Z, timezone, and timezone offset
     * 
     * @example <caption>Initialize the component with the <code class="prettyprint">value</code> option:</caption>
     * <input id="date" data-bind="ojComponent: {component: 'ojInputDateTime', value: '2014-09-10T13:30:00.000'}" />
     * @example <caption>Initialize the component with the <code class="prettyprint">value</code> option specified programmatically 
     * using oj.IntlConverterUtils.dateToLocalIso :</caption>
     * $(".selector").ojInputDateTime({'value': oj.IntlConverterUtils.dateToLocalIso(new Date())});<br/>
     * @example <caption>Get or set the <code class="prettyprint">value</code> option, after initialization:</caption>
     * // Getter: returns Today's date in ISOString
     * $(".selector").ojInputDateTime("option", "value");
     * // Setter: sets it to a different date
     * $(".selector").ojInputDateTime("option", "value", oj.IntlConverterUtils.dateToLocalIso(new Date(2013, 0, 1, 0, 0, 0, 0)));
     * 
     * @expose 
     * @name value
     * @instance
     * @memberof! oj.ojInputDateTime
     * @default When the option is not set, the element's value property is used as its initial value 
     * if it exists. This value must be a local ISOString meaning lacking Z, timezone, and timezone offset.
     */
  },
  
  /**
   * @protected
   * @override
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  _InitBase : function __InitBase() 
  {
    this._super();
    
    this._timePickerElement = this.element; //if the ojInputDateTime is inline, then this ref will change to a NEW input element
    this._timePicker = null;
    this._timeConverter = null;
    
    //need to remember the last _SetValue for the case of timepicker [i.e. select a date that is not in range due to 
    //time; however since we don't push invalid values to this.options["value"] the timepicker would pick up the wrong 
    //selected date
    this._previousValue = null;
  },
  
  /**
   * @protected
   * @override
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  _ComponentCreate : function __ComponentCreate()
  {
    var ret = this._super(), 
        timeConverter = this._getTimePickerConverter(this._GetConverter());
    
    if (timeConverter === null)
    {
      throw new Error("Please use ojInputDate if you do not have time portion");
    }
    
    if (this._isInLine)
    {
      //Since DatePicker never intended to have timepicker associated to it
      //need to have an input element that is tied to the time selector
      
      //@HTMLUpdateOK
      var input = $("<input type='text'>");
      input.insertAfter(this.element);
      
      //Now need to reset this._timePickerElement to the newly created input element
      this._timePickerElement = input;
    }
    
    var passOptions = ["title", "placeholder", "disabled", "required", "readOnly"],
        passObject = {};
        
    for(var i=0, j=passOptions.length; i < j; i++) 
    {
      passObject[passOptions[i]] = this.options[passOptions[i]];
    }
    
    var messagesDisplayOption = this.options['displayOptions']['messages'];
    
    //create time instance for the time portion
    // jmw Seems to be a bug where messages are always in notewindow. So I think I should
    // carry the displayOptions over to the timePicker.
    this._timePicker = this._timePickerElement.ojInputTime(
    $.extend(passObject, {
      "converter" : timeConverter,
      "displayOptions" : {"converterHint": "none", "title": "none", "messages": messagesDisplayOption},
      "value": oj.IntlConverterUtils.dateToLocalIso(this._getDate()),
      "timePicker" : this.options["timePicker"], 
      "datePickerComp" : {"widget": this, "inline": this._isInLine} 
    }));
    
    return ret;
  },
  
  _setOption : function __setOption(key, value, flags)
  {
    var retVal = this._superApply(arguments);
    
    if (key === "value") 
    {
      //if goes through model does it needs to update or should be only used by selection + keydown
      this._previousValue = value;
    }
    
    if(this._timePicker) 
    {
      var timeInvoker = {"disabled": true, "readOnly": true};
      
      if (key in timeInvoker)
      {
        this._timePicker.ojInputTime("option", key, value);
      }
      else if(key === "timePicker")
      {
        this._timePicker.ojInputTime("option", "timePicker.timeIncrement", value["timeIncrement"]);
      }
      else if (key === "converter")
      {
        this._timeConverter = null;
        this._timePicker.ojInputTime("option", key, this._getTimePickerConverter(this._GetConverter())); //need to invoke _GetConverter for the case when null and etc sent in
      }
    }
    
    return retVal;
  },
  
  /**
   * @ignore
   * @protected
   * @override
   */
  _destroy : function __destroy()
  {
    var ret = this._super();

    this._timePicker.ojInputTime("destroy");

    if (this._isInLine)
    {
      //note that this.element below would be of the TimePicker's input element
      this._timePickerElement.remove();
    }
    
    return ret;
  },
  
  /*
   * Will provide the timePicker converter based on the actual converter
   */
  _getTimePickerConverter : function __getTimePickerConverter(converter) 
  {
    if(this._timeConverter !== null) 
    {
      return this._timeConverter;
    }
    
    var resolvedOptions = converter.resolvedOptions(), options = { },
        params = ["hour", "hour12", "minute", "second", "millisecond", "timeFormat"], i, j;

    for (i = 0, j = params.length;i < j;i++)
    {
      if (params[i] in resolvedOptions)
      {
        if(params[i] === "timeFormat") {
          //special case for timeFormat, formatType of time must be added
          options["formatType"] = "time";
        }
        options[params[i]] = resolvedOptions[params[i]];
      }
    }
    
    if ($.isEmptyObject(options))
    {
      throw new Error("Plase use ojInputDateTime's converter is lacking the time portion");
    }
    
    var timeConverter = oj.Validation.converterFactory(oj.ConverterFactory.CONVERTER_TYPE_DATETIME).createConverter(options);
    this._timeConverter = timeConverter;
    return timeConverter;
  },
  
  /**
   * Handler for when the time is selected. Should be invoked ONLY by the ojInputTime component
   * 
   * @ignore
   * @param {string} newValue
   * @param {Event} event
   */
  timeSelected : function __timeSelected(newValue, event)
  {
    
    this._SetDisplayValue( this._GetConverter()["format"](newValue) );
    this._SetValue(newValue, event);
  },
  
  /**
   * Provides the current displayed selected value for ojInputTime component [i.e. when is invalid return this._previousValue]
   * The complication occurs b/c we do not push invalid values to the model and b/c of that reason this.options["value"] 
   * might contain outdated isoString for ojInputTime. For instance let's say the min date is 02/01/14 2PM then 
   * when an user selects 02/01/14 the component would be invalid and the value would not be pushed. However one needs 
   * to give opportunity for ojInputTime to allow user in selecting the valid datetime in full so the _previousValue 
   * must be passed through.
   * 
   * @ignore
   */
  getValueForInputTime : function __getValueForInputTime()
  {
    return this.isValid() ? this.options["value"] : (this._previousValue ? this._GetConverter()["parse"](this._previousValue) : null);
  },
  
  /**
   * @ignore
   * @protected
   * @override
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  _SetValue : function __SetValue(newValue, event, options)
  {
    this._superApply(arguments);
    
    this._previousValue = newValue;
  },
  
  /**
   * Just for the case of launching timepicker with Shift + Up or Shift + Down
   * 
   * @ignore
   * @protected
   * @override
   * @param {Event} event
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  _onKeyDownHandler : function __onKeyDownHandler(event) 
  {
    var kc = $.ui.keyCode, 
        handled = false;
    
    switch (event.keyCode)
    {
      case kc.UP: ;
      case kc.DOWN:
        if(event.shiftKey)
        {
          this._SetValue(this._GetDisplayValue(), event);
          this._timePicker.ojInputTime("show");
          handled = true;
        }
        break;
      default: ;
    }

    if (handled)
    {
      event.preventDefault();
      event.stopPropagation();
      return false;
    }
    
    return this._superApply(arguments);
  },
  
  /**
   * @ignore
   * @expose
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  show : function __show()
  {
    this._timePicker.ojInputTime("hide");
    return this._super();
  },
  
  /**
   * Method to show the internally created ojInputTime
   * 
   * @expose
   * @memberof! oj.ojInputDateTime
   * @instance
   */
  showTimePicker : function __showTimePicker()
  {
    this.hide();
    return this._timePicker.ojInputTime("show");
  },
  
  /**
   * Method to hide the internally created ojInputTime
   * 
   * @expose
   * @memberof! oj.ojInputDateTime
   * @instance
   */
  hideTimePicker : function __hideTimePicker()
  {
    return this._timePicker.ojInputTime("hide");
  },
  
  /** 
   * @ignore
   * @override
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  refresh : function __refresh()
  {
    var retVal = this._superApply(arguments) || this;
    
    this._timePicker.ojInputTime("refresh");
    
    return retVal;
  },
  
  /**
   * Return the subcomponent node represented by the documented locator attribute values. <br/>
   * If the locator is null or no subId string is provided then this method returns the element that 
   * this component was initalized with. <br/>
   * If a subId was provided but a subcomponent node cannot be located this method returns null.
   * 
   * <p>If the <code class="prettyprint">locator</code> or its <code class="prettyprint">subId</code> is 
   * <code class="prettyprint">null</code>, then this method returns the element on which this component was initalized.
   * 
   * <p>If a <code class="prettyprint">subId</code> was provided but no corresponding node 
   * can be located, then this method returns <code class="prettyprint">null</code>.
   * 
   * @expose
   * @override
   * @memberof oj.ojInputDateTime
   * @instance
   * 
   * @param {Object} locator An Object containing, at minimum, a <code class="prettyprint">subId</code> 
   * property. See the table for details on its fields.
   * 
   * @property {string=} locator.subId - A string that identifies a particular DOM node in this component.
   * 
   * <p>The supported sub-ID's are documented in the <a href="#subids-section">Sub-ID's</a> section of this document.
   * 
   * @property {number=} locator.index - A zero-based index, used to locate a message content node 
   * or a hint node within the popup. 
   * @returns {Element|null} The DOM node located by the <code class="prettyprint">subId</code> string passed in 
   * <code class="prettyprint">locator</code>, or <code class="prettyprint">null</code> if none is found.
   * 
   * @example <caption>Get the node for a certain subId:</caption>
   * var node = $( ".selector" ).ojInputDateTime( "getNodeBySubId", {'subId': 'oj-some-sub-id'} );
   */
  getNodeBySubId: function(locator)
  {
    var subId = locator && locator['subId'],
        node = null;
    
    if(subId) 
    {
      if(subId === "oj-listbox-drop" || subId === "oj-inputdatetime-time-icon") 
      {
        node = this._timePicker.ojInputTime("getNodeBySubId", locator);
      }
      else if(subId === "oj-inputdatetime-date-input") 
      {
        node = this._isInLine ? this._timePickerElement[0] : this.element[0];
      }
    }
    
    return node || this._superApply(arguments);
  },
  
  /**
   * Returns the subId string for the given child DOM node.  For more details, see 
   * <a href="#getNodeBySubId">getNodeBySubId</a>.
   * 
   * @expose
   * @override
   * @memberof oj.ojInputDateTime
   * @instance
   * 
   * @param {!Element} node - child DOM node
   * @return {string|null} The subId for the DOM node, or <code class="prettyprint">null</code> when none is found.
   * 
   * @example <caption>Get the subId for a certain DOM node:</caption>
   * // Foo is ojInputNumber, ojInputDate, etc.
   * var subId = $( ".selector" ).ojFoo( "getSubIdByNode", nodeInsideComponent );
   */
  getSubIdByNode: function(node)
  {
    var dateTimeSpecific = null;
    
    if(this._isInLine) 
    {
      if(node === this._timePickerElement[0]) 
      {
        dateTimeSpecific = "oj-inputdatetime-date-input";
      }
    }
    else 
    {
      if(node === this.element[0]) 
      {
        dateTimeSpecific = "oj-inputdatetime-date-input";
      }
    }
    
    return dateTimeSpecific || this._timePicker.ojInputTime("getSubIdByNode", node) || this._superApply(arguments);
  },
  
  /**
   * Need to override since apparently 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.ojInputDateTime
   * @instance
   * @protected
   * @override
   */
  _GetConverter : function () 
  {
    return this.options['converter'] ? 
            this._superApply(arguments) :
            $["oj"]["ojInputDateTime"]["prototype"]["options"]["converter"];
  },
  
  /**
   * Notifies the component that its subtree has been removed from the document programmatically after the component has
   * been created
   * @memberof! oj.ojInputDateTime
   * @instance
   * @protected 
   */
  _NotifyDetached: function()
  {
    this._superApply(arguments);
    
    if(this._timePicker) 
    {
      this.hideTimePicker();
    }
  },

  /**
   * Notifies the component that its subtree has been made hidden programmatically after the component has
   * been created
   * @memberof! oj.ojInputDateTime
   * @instance
   * @protected 
   */
  _NotifyHidden: function()
  {
    this._superApply(arguments);
    
    if(this._timePicker) 
    {
      this.hideTimePicker();
    }
  },
  
  /**
   * 
   * @return {Object} jquery object 
   * 
   * 
   * @expose
   * @protected
   * @override
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  _GetMessagingLauncherElement : function ()
  {
    return !this._isInLine ? this._super() : this._timePickerElement;
  },
  
  /**
   * @protected
   * @override
   * @instance
   * @memberof! oj.ojInputDateTime
   * @return {string}
   */
  _GetDefaultStyleClass : function ()
  {
    return "oj-inputdatetime";
  },
  
  /**
   * @protected
   * @override
   * @instance
   * @memberof! oj.ojInputDateTime
   */
  _GetTranslationsSectionName: function()
  {
    return "oj-ojInputDate"; 
  }
  
});