/**
* Copyright (c) 2014, Oracle and/or its affiliates.
* All rights reserved.
*/
/**
* @ojcomponent oj.ojSelect
* @augments oj.editableValue
* @since 0.6
*
* @classdesc
* <h3 id="selectOverview-section">
* JET Select Component
* <a class="bookmarkable-link" title="Bookmarkable Link" href="#selectOverview-section"></a>
* </h3>
*
* <p>Description: JET Select enhances a html select and option elements into a Select that supports
* single-select and search filtering. Note: Muliple selection is not supported in V1.
*
* <p>A JET Select can be created with the following markup. By default, it creates a single-select
* Select.
*
* <pre class="prettyprint">
* <code>
* <select data-bind="ojComponent: {component: 'ojSelect'}">
* <option value="option 1">option 1</option>
* <option value="option 2">option 2</option>
* <option value="option 3">option 3</option>
* <option value="option 4">option 4</option>
* </select>
* </code></pre>
*
* <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="rtl-section">
* Reading direction
* <a class="bookmarkable-link" title="Bookmarkable Link" href="#rtl-section"></a>
* </h3>
*
* <p>As with any JET component, in the unusual case that the directionality (LTR or RTL) changes post-init, the Select must be <code class="prettyprint">refresh()</code>ed.
*
*
* <h3 id="pseudos-section">
* Pseudo-selectors
* <a class="bookmarkable-link" title="Bookmarkable Link" href="#pseudos-section"></a>
* </h3>
*
* <p>The <code class="prettyprint">:oj-select</code> pseudo-selector can be used in jQuery expressions to select JET Select. For example:
*
* <pre class="prettyprint">
* <code>$( ":oj-select" ) // selects all JET Select on the page
* $myEventTarget.closest( ":oj-select" ) // selects the closest ancestor that is a JET Select
* </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 select component.
* For select, you should put an <code>id</code> on the select, and then set
* the <code>for</code> attribute on the label to be the select's id.
* </p>
* <h3 id="label-section">
* Label and Select
* <a class="bookmarkable-link" title="Bookmarkable Link" href="#label-section"></a>
* </h3>
* <p>
* For accessibility, you should associate a label element with the select
* by putting an <code>id</code> on the select, and then setting the
* <code>for</code> attribute on the label to be the select'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="jqui2jet-section">
* JET for jQuery UI developers
* <a class="bookmarkable-link" title="Bookmarkable Link" href="#jqui2jet-section"></a>
* </h3>
*
* <p>Event names for all JET components are prefixed with "oj", instead of component-specific prefixes like "Select".
*
* @desc Creates a JET Select.
* @example <caption>Initialize the Select with no options specified:</caption>
* $( ".selector" ).ojSelect();
*
* @example <caption>Initialize the Select with some options:</caption>
* $( ".selector" ).ojSelect( { "placeholder": "Select a value." } );
*
* @example <caption>Initialize the Select via the JET <code class="prettyprint">ojComponent</code> binding:</caption>
* <div id="select" data-bind="ojComponent: { component: 'ojSelect' }">
*/
oj.__registerWidget("oj.ojSelect", $['oj']['editableValue'],
{
defaultElement : "<select>",
widgetEventPrefix : "oj",
options :
{
/**
* The threshold for showing the search box in the dropdown when it's expanded.
* The search box is always displayed when the results size is greater than
* the threshold, otherwise the search box is initially turned off.
* However, the search box is displayed as soon as the user starts typing.
* This property only applies to single-select.
*
* @expose
* @memberof! oj.ojSelect
* @instance
* @type {number}
* @default <code class="prettyprint">10</code>
*/
minimumResultsForSearch : 10,
/**
* The placeholder text to set on the element.<p>
* If the <code class="prettyprint">placeholder</code> option is specified to a string, ojselect will adds a placeholder item at the beginning of the dropdown list with
*<ul>
*<li>displayValue: placeholder text</li>
*<li>value: an empty string</li>
*</ul>
* The placeholder item in the dropdown is selectable. However, it's not a valid choice, i.e. validation will fail if the select component is a required field.<p>
* The placeholder item doesn't participate in the filtering, so it will not appear in the result list with a filter specified.<p>
* Placeholder text can be an empty string, please see the select placeholder cookbook demo.
*
* @example <caption>Initialize the select with the <code class="prettyprint">placeholder</code> option specified:</caption>
* $( ".selector" ).ojSelect( { "placeholder": "Please select ..." } );
*
* @default <code class="prettyprint">undefined</code>
*
* @expose
* @access public
* @instance
* @memberof! oj.ojSelect
* @type {string|null|undefined}
*/
placeholder: undefined,
/**
* The id of the html list for the select.
*
* @example <caption>Initialize the select with the <code class="prettyprint">list</code> option specified:</caption>
* $( ".selector" ).ojSelect( { "list": "list" } );
*
* @example <caption>The <code class="prettyprint">list</code> points to a html <code class="prettyprint">ul</code> element.
* The value for the list item should be specified with <code class="prettyprint">oj-data-value</code> field. By default, we use the first text node for search filtering. An optional <code class="prettyprint">oj-data-label</code> field can be added to the list item, in which case it will take precedence over the text node.</caption></caption>
* <ul id="list">
* <li oj-data-value="li1">Item 1</li>
* <li oj-data-value="li2">Item 2</li>
* </ul>
*
* @expose
* @memberof! oj.ojSelect
* @instance
* @type {string|null|undefined}
*/
list: undefined,
/**
* If multi-select is enabled for the select.
*
* @expose
* @memberof! oj.ojSelect
* @instance
* @type {boolean}
* @default <code class="prettyprint">false</code>
*
* @example <caption>Initialize the Select with the <code class="prettyprint">multiple</code> option specified:</caption>
* $( ".selector" ).ojSelect( { "multiple": true } );
*/
multiple: false,
/**
* The option items for the Select. Instead of providing a list of option items, they can be specified as an array of objects containing value and label.
* The value is used as the value of the option item and label as the label.
*
* @expose
* @memberof! oj.ojSelect
* @instance
* @type {Array}
*
* @example <caption>Initialize the Select with the <code class="prettyprint">options</code> option specified:</caption>
* $( ".selector" ).ojSelect( { "options": [{value: 'option1', label: 'option1'}, {value: 'option2', label: 'option2'}, {value: 'option3', label: 'option3'},] } );
* @example <caption>Initialize the Select with group data:</caption>
* $( ".selector" ).ojSelect( { "options": [{label : 'group1', children: [{value: 'option1', label: 'option1'}, {value: 'option2', label: 'option2'}]}, {label: 'group2', children: [{value: 'option3', label: 'option3'}]} ] } );
*/
options : null,
/**
* Specify the key names to use in the options array.
*
* @expose
* @memberof! oj.ojSelect
* @instance
* @type {Object}
*
* @example <caption>Initialize the Select with <code class="prettyprint">optionsKeys</code> specified. This allows the key names to be redefined in the options array.</caption>
* $( ".selector" ).ojSelect( { "optionsKeys": {value : "state_abbr", label : "state_name"} } );
* @example <caption>Redefine keys for data with subgroups.</caption>
* $( ".selector" ).ojSelect( { "optionsKeys": {label : "regions", children : "states", childKeys : {value : "state_abbr", label : "state_name"}} } );
*/
optionsKeys : null,
/**
* Triggered immediately before the Select drop down is expanded.
*
* @expose
* @event
* @memberof! oj.ojSelect
* @instance
* @property {Event} event <code class="prettyprint">jQuery</code> event object
* @property {Object} ui Parameters
*
* @example <caption>Initialize the Select with the <code class="prettyprint">beforeExpand</code> callback specified:</caption>
* $( ".selector" ).ojSelect({
* "beforeExpand": function( event ) {}
* });
*
* @example <caption>Bind an event listener to the <code class="prettyprint">ojbeforeexpand</code> event:</caption>
* $( ".selector" ).on( "ojbeforeexpand", function( event, ui ) {} );
*/
beforeExpand : null
/**
* The value of the select component. The data type of value is array. Only the first element of the array is used.
*
* Note: <code class="prettyprint">value</code> option can only be bind to a knockout observableArray.
*
* @example <caption>Initialize the select with the <code class="prettyprint">value</code> option specified:</caption>
* $(".selector").ojSelect({"value": ["option1"]});<br/>
*
* @example <caption>Get or set the <code class="prettyprint">value</code> option, after initialization:</caption>
* // Getter: returns value
* $(".selector").ojSelect("option", "value");
* // Setter: sets value with array containing "option1"
* $(".selector").ojSelect("option", "value", ["option1"]);
*
* @member
* @name value
* @access public
* @instance
* @default When the value option is not set, the first option is used as its initial value if it exists.
* @memberof! oj.ojSelect
* @type {Array}
*/
},
/**
* Returns a jQuery object containing the element visually representing the select.
*
* <p>This method does not accept any arguments.
*
* @expose
* @memberof! oj.ojSelect
* @instance
* @return {jQuery} the select
*/
widget : function ()
{
return this.select.container;
},
/**
* @override
* @private
* @memberof! oj.ojSelect
*/
_ComponentCreate : function ()
{
this._super();
this._setup();
},
//ojselect
_setup : function ()
{
var opts = {},
multiple = this.options.multiple;
opts.element = this.element;
opts.ojContext = this;
opts = $.extend(this.options, opts);
this.select = multiple ? new _OjMultiSelect() : new _OjSingleSelect();
this.select._init(opts);
},
/**
* Refreshes the visual state of the select. JET components require a <code class="prettyprint">refresh()</code> or re-init after the DOM is programmatically changed underneath the component.
*
* <p>This method does not accept any arguments.
*
* @expose
* @memberof! oj.ojSelect
* @instance
*/
refresh : function ()
{
this._super();
this.select._destroy();
this._setup();
//TODO: apply value in options for the selected value
//re apply root attributes settings
this._SetRootAttributes();
// re-apply oj-required on container
this._Refresh("required", this.options['required']);
},
/**
* @override
* @private
* @memberof! oj.ojSelect
*/
_destroy : function ()
{
//Bug 20020271 - select destroy issue
this.select._destroy();
this._super();
},
//19670760, dropdown popup should be closed on subtreeDetached notification.
_NotifyDetached : function() {
this.select.close();
},
//19670760, dropdown popup should be closed on subtreeHidden notification.
_NotifyHidden : function() {
this.select.close();
},
/**
* Set the placeholder.
* @override
* @protected
* @memberof! oj.ojSelect
*/
_SetPlaceholder : function(value)
{
/*
* Commented out the content to fix the side effect from
* the change made in EditableValue._initComponentMessaging (Revision: 9016).
* EditableValue called SetPlaceholder with an empty string which made
* every ojselect to have an empty placeholder in the dropdown.
* Note: don't remove the method because there is more calls from EditableValue
* to ojselect before this.select is initialized.
* ex: _GetContentElement
if (this.select)
{
this.select.opts.placeholder = value;
this.select._setPlaceholder();
}
*/
},
/**
* whether the placeholder option is set
*
* @memberof! oj.ojSelect
* @instance
* @protected
*/
_HasPlaceholderSet : function()
{
//Bug 18926010 - an empty placeholder shows up if data changed after first binding
return typeof this.options['placeholder'] === 'string';
},
/**
* Clear the placeholder option
*
* @memberof! oj.ojSelect
* @instance
* @protected
*/
_ClearPlaceholder : function()
{
//Bug 18926010 - an empty placeholder shows up if data changed after first binding
this._SetPlaceholderOption(null);
this._SetPlaceholder(null);
},
//ojselect
_InitOptions : function (originalDefaults, constructorOptions)
{
var props = [{attribute: "disabled", defaultOptionValue: null, validateOption: true},
{attribute: "placeholder", defaultOptionValue: null},
{attribute: "required", defaultOptionValue: false,
coerceDomValue: true, validateOption: true},
{attribute: "title", defaultOptionValue: ""}
// {attribute: "value", defaultOptionValue: null}
];
this._super(originalDefaults, constructorOptions);
oj.EditableValueUtils.initializeOptionsFromDom(props, constructorOptions, this);
// TODO: PAVI - Let's discuss
if (this.options['value'] === undefined) {
this.options['value'] = (this.element.attr('value') !== undefined) ? _ComboUtils.splitVal(this.element.val(), ",") : null;
}
else {
//clone the value, otherwise _setDisplayValue will not be invoked on binding value to ko observableArray.
//TODO: Need to revisit this once 18724975 is fixed.
var value = this.options['value'];
if (Array.isArray(value)) {
value = value.slice(0);
}
/*
else if(typeof value ==='string') {
value = [value];
}
*/
this.options['value'] = value;
}
},
/**
* Validates the component's value using the converter and all validators registered on
* the component.
*
* @expose
* @override
* @memberof! oj.ojSelect
* @instance
* @returns {boolean} true if component passed validation, false if there were validation errors.
*/
validate : function ()
{
//Bug 19231311 - select needs implementation fixes...
if (this.select)
return this._SetValue(this.select.getVal(), null, this._VALIDATE_METHOD_OPTIONS);
return true;
},
/**
* Updates display value.
* @override
* @protected
* @memberof! oj.ojSelect
*/
_SetDisplayValue: function(displayValue)
{
this.select._initSelection();
},
/**
* Handles options specific to select.
* @override
* @protected
* @memberof! oj.ojSelect
*/
_setOption : function (key, value, flags)
{
if (key === "value") {
//clone the value, otherwise _setDisplayValue will not be invoked on binding value to ko observableArray.
//TODO: Need to revisit this once 18724975 is fixed.
//placeholder
if (this._HasPlaceholderSet() && value && value.length == 0) {
this._super(key, value, flags);
return;
}
var strVal = value;
if (Array.isArray(value)) {
value = value.slice(0);
//Bug 20957774 - ojselect doesn't update when bound value is modified
if (this.options['multiple'] !== true)
strVal = value[0];
}
//Bug 19074312 - ojselect should ignore the invalid value set programmatically
var element = this.select.datalist;
if (! element)
element = this.select.opts.element;
//return if validation failed
if ((this.options['multiple'] !== true && this.select.opts.validate(element, strVal))
|| this.options['multiple'])
this._super(key, value, flags);
return;
}
else if (key === "placeholder")
{
this.select.opts.placeholder = value;
this.select._setPlaceholder();
}
else if (key === "minimumResultsForSearch")
{
this.select.opts.minimumResultsForSearch = value;
}
this._super(key, value, flags);
if (key === "disabled")
{
if (value)
this.select._disable();
else
this.select._enable();
}
else if (key === "options")
{
//Bug 18926010 - an empty placeholder shows up if data changed after first binding
//Bug 19941308 - ojselect - validator error message is not shown
//Bug 19977578 - ojselect tooltip no longer appears once options and value observables change
this.select.opts.options = value;
this.select.opts = this.select._prepareOpts(this.select.opts);
//make sure the value still valid
this._super("value", this.select.getVal());
}
},
_getDropdown : function ()
{
if (this.select && this.select._opened())
{
//Bug 20747359 - certain subids does not work inside a popup or dialog
var dropdown = this.select.dropdown;
if (dropdown &&
dropdown.attr("data-oj-containerid") === this.select.containerId)
return dropdown;
}
return null;
},
////////////////// SUB-IDS //////////////////
/**
* <p>Sub-ID for the selected text in the select box
*
* <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and
* <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
*
* @ojsubid
* @member
* @name oj-select-chosen
* @memberof oj.ojSelect
* @instance
*
* @example <caption>Get the selected text</caption>
* var node = $( ".selector" ).ojSelect( "getNodeBySubId", {'subId': 'oj-select-chosen'} );
*/
/**
* <p>Sub-ID for the dropdown box.
* <p>See the <a href="#minimumResultsForSearch">minimumResultsForSearch</a> option for details.
* <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and
* <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
*
* @ojsubid
* @member
* @name oj-select-drop
* @memberof oj.ojSelect
* @instance
*
* @example <caption>Get the dropdown box</caption>
* var node = $( ".selector" ).ojSelect( "getNodeBySubId", {'subId': 'oj-select-drop'} );
*/
/**
* <p>Sub-ID for the search box. Note: the search box is not always visible.
* <p>See the <a href="#minimumResultsForSearch">minimumResultsForSearch</a> option for details.
* <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and
* <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
*
* @ojsubid
* @member
* @name oj-select-search
* @memberof oj.ojSelect
* @instance
*
* @example <caption>Get the search box</caption>
* var node = $( ".selector" ).ojSelect( "getNodeBySubId", {'subId': 'oj-select-search'} );
*/
/**
* <p>Sub-ID for the search input element. Note that the search input is not always visible.
* <p>See the <a href="#minimumResultsForSearch">minimumResultsForSearch</a> option for details.
* <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and
* <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
*
* @ojsubid
* @member
* @name oj-listbox-input
* @memberof oj.ojSelect
* @instance
*
* @example <caption>Get the search input element</caption>
* var node = $( ".selector" ).ojSelect( "getNodeBySubId", {'subId': 'oj-listbox-input'} );
*/
/**
* <p>Sub-ID for the filtered result list.
* <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and
* <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
*
* @ojsubid
* @member
* @name oj-select-results
* @memberof oj.ojSelect
* @instance
*
* @example <caption>Get the filtered result list</caption>
* var node = $( ".selector" ).ojSelect( "getNodeBySubId", {'subId': 'oj-select-results'} );
*/
/**
* <p>Sub-ID for the filtered result item.
* <p>Note: To lookup a filtered result item, the dropdown must be open and
* the locator object should have the following:<p>
* subId: 'oj-listbox-result-label' and
* index: number
* <p>See the <a href="#getNodeBySubId">getNodeBySubId</a> and
* <a href="#getSubIdByNode">getSubIdByNode</a> methods for details.
*
* @ojsubid
* @member
* @name oj-listbox-result-label
* @memberof oj.ojSelect
* @instance
*
* @example <caption>Get the filtered result item</caption>
* var node = $( ".selector" ).ojSelect( "getNodeBySubId", {'subId': 'oj-listbox-result-label'} );
*/
getNodeBySubId: function(locator)
{
var node = null, subId;
if (locator == null)
{
return this.select.container ? this.select.container[0] : null;
}
else
{
node = this._super(locator);
}
if (!node)
{
subId = locator['subId'];
if (subId === "oj-select-drop")
subId = "oj-listbox-drop";
if (subId === "oj-select-results")
subId = "oj-listbox-results";
if (subId === "oj-select-search")
subId = "oj-listbox-search";
switch (subId) {
case "oj-select-choice":
case "oj-select-chosen":
node = this.widget().find("." + subId)[0];
break;
case "oj-listbox-drop":
var dropdown = this._getDropdown();
if (dropdown) {
node = dropdown[0];
}
break;
case "oj-listbox-input":
case "oj-listbox-search":
case "oj-listbox-results":
var dropdown = this._getDropdown();
if (dropdown) {
node = dropdown.find("." + subId)[0];
}
break;
//Bug 18872085 - ojselect - not able to attach id for generated jet component
case "oj-listbox-result-label":
if (this._getDropdown())
{
//list of 'li'
var ddlist = $("#" + this.select.results.attr("id")).children();
var index = locator['index'];
if (ddlist.length && index < ddlist.length) {
node = ddlist.eq(index).find("." + subId)[0];
}
}
break;
}
}
// Non-null locators have to be handled by the component subclasses
return node || null;
},
/**
* Returns the default styleclass for the component. Currently this is
* used to pass to the _ojLabel component, which will append -label and
* add the style class onto the label. This way we can style the label
* specific to the input component. For example, for inline labels, the
* radioset/checkboxset components need to have margin-top:0, whereas all the
* other inputs need it to be .5em. So we'll have a special margin-top style
* for .oj-label-inline.oj-radioset-label
* All input components must override
*
* @return {string}
* @expose
* @memberof! oj.ojSelect
* @override
* @protected
*/
_GetDefaultStyleClass : function ()
{
return "oj-select";
},
/**
* Returns the messaging launcher element i.e., where user sets focus that triggers the popup.
* Usually this is the element input or select that will receive focus and on which the popup
* for messaging is initialized.
*
* @override
* @protected
* @memberof! oj.ojSelect
* @return {Object} jquery element which represents the messaging launcher component
*/
_GetMessagingLauncherElement : function ()
{
return this.select.selection;
},
/**
* Returns the jquery element that represents the content part of the component.
* This is usually the component that user sets focus on (tabindex is set 0) and
* where aria attributes like aria-required, aria-labeledby etc. are set. This is
* also the element where the new value is updated. Usually this is the same as
* the _GetMessagingLauncherElement.
*
* @override
* @protected
* @memberof! oj.ojSelect
* @return {Object} jquery element which represents the content.
*/
_GetContentElement : function ()
{
return this.select.selection;
}
// Fragments:
/**
* <table class="keyboard-table">
* <thead>
* <tr>
* <th>Target</th>
* <th>Gesture</th>
* <th>Action</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>Select box or Arrow button</td>
* <td><kbd>Tap</kbd></td>
* <td>If the drop down is not open, expand the drop down list. Otherwise, close the drop down list.</td>
* </tr>
* <tr>
* <td>Option item</td>
* <td><kbd>Tap</kbd></td>
* <td>Tap on a option item in the drop down list to select.</td>
* </tr>
* <tr>
* <td>Selected Item with Clear Entry Button</td>
* <td><kbd>Tap</kbd></td>
* <td>Remove item from the selected items list by taping on the clear button next to the data item.</td>
* </tr>
* <tr>
* <td>Drop down</td>
* <td><kbd>swipe up/down</kbd></td>
* <td>Scroll the drop down list vertically</td>
* </tr>
* </tbody>
* </table>
*
* @ojfragment touchDoc - Used in touch gesture section of classdesc, and standalone gesture doc
* @memberof oj.ojSelect
*/
/**
* <table class="keyboard-table">
* <thead>
* <tr>
* <th>Target</th>
* <th>Key</th>
* <th>Action</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>Option item</td>
* <td><kbd>Enter</kbd></td>
* <td>Select the highlighted choice from the drop down list.</tr>
* </tr>
* <tr>
* <td>Drop down</td>
* <td><kbd>UpArrow or DownArrow</kbd></td>
* <td>Highlight the option item in the direction of the arrow. If the drop down is not open, expand the drop down list.</tr>
* </tr>
* <tr>
* <td>Drop down</td>
* <td><kbd>Esc</kbd></td>
* <td>Collapse the drop down list. If the drop down is already closed, do nothing.</tr>
* </tr>
* </tbody>
* </table>
*
* <p>Disabled option items receive no highlight and are not selectable.
*
* @ojfragment keyboardDoc - Used in keyboard section of classdesc, and standalone gesture doc
* @memberof oj.ojSelect
*/
}
);
oj.Components.setDefaultOptions(
{
// converterHint is defaulted to placeholder and notewindow in EditableValue.
// For ojselect, we don't want a converterHint.
// We used to use oj.Components.createDynamicPropertyGetter, but we don't need the 'context' yet,
// so we switched it to this simplest code so that overriding displayOptions
// for defaultOptions is easier. We only need to define what we want to override, not
// re-define all the sub-options of displayOptions.
// See Bug 20441549 - allow multiple setdefaultoptions calls on properties with dynamic getter.
'ojSelect': // properties for all ojSelect components
{
'displayOptions':
{
'converterHint': ['none']
}
}
}
);
Source: src/main/javascript/oracle/oj/ojselectcombobox/ojselect.js
Oracle® JavaScript Extension Toolkit (JET)
1.1.2
E65298-01