$.fn.romoPicker = function() { return $.map(this, function(element) { return new RomoPicker(element); }); } var RomoPicker = function(element) { this.elem = $(element); this.defaultCaretClass = undefined; this.defaultCaretPaddingPx = 5; this.defaultCaretPosition = 'right' this.defaultValuesDelim = ','; this.defaultOptionItems = this._buildDefaultOptionItems(); this.filteredOptionItems = []; this.doInit(); this._bindElem(); this.doSetValue(this._elemValues()); if (this.elem.attr('id') !== undefined) { $('label[for="'+this.elem.attr('id')+'"]').on('click', $.proxy(function(e) { this.romoOptionListDropdown.doFocus(); }, this)); } $(window).on("pageshow", $.proxy(function(e) { this._refreshUI(); }, this)); this.elem.on('romoPicker:triggerSetValue', $.proxy(function(e, value) { this.doSetValue(value) }, this)); this.elem.trigger('romoPicker:ready', [this]); } RomoPicker.prototype.doInit = function() { // override as needed } RomoPicker.prototype.doSetValue = function(values) { var value = undefined; if (Array.isArray(values)) { value = values.join(this._elemValuesDelim()); } else { value = values; } $.ajax({ type: 'GET', url: this.elem.data('romo-picker-url'), data: { 'values': value }, success: $.proxy(function(data, status, xhr) { this.doSetValueDatas(data); }, this), }); } RomoPicker.prototype.doSetValueDatas = function(valueDatas) { var datas = undefined; if (Array.isArray(valueDatas)) { datas = valueDatas; } else { datas = [valueDatas]; } var values = datas.map(function(data) { return data.value; }); var displayTexts = datas.map(function(data) { return data.displayText; }); if (this.romoSelectedOptionsList !== undefined) { this._setValuesAndDisplayText(values, ''); this.romoSelectedOptionsList.doSetItems(datas); } else { this._setValuesAndDisplayText( values, (displayTexts[0] || this.elem.data('romo-picker-empty-option-display-text') || '') ); this.romoOptionListDropdown.doSetSelectedItem(values[0]); } this._refreshUI(); } /* private */ RomoPicker.prototype._bindElem = function() { this._bindOptionListDropdown(); this._bindSelectedOptionsList(); this._bindAjax(); this.elem.on('romoPicker:triggerToggle', $.proxy(function(e) { this.romoOptionListDropdown.elem.trigger('romoOptionListDropdown:triggerToggle', []); }, this)); this.elem.on('romoPicker:triggerPopupOpen', $.proxy(function(e) { this.romoOptionListDropdown.elem.trigger('romoOptionListDropdown:triggerPopupOpen', []); }, this)); this.elem.on('romoPicker:triggerPopupClose', $.proxy(function(e) { this.romoOptionListDropdown.elem.trigger('romoOptionListDropdown:triggerPopupClose', []); }, this)); this.romoOptionListDropdown.doSetListItems(this.defaultOptionItems); } RomoPicker.prototype._bindSelectedOptionsList = function() { this.romoSelectedOptionsList = undefined; if (this.elem.prop('multiple') === true) { if (this.elem.data('romo-picker-multiple-item-class') !== undefined) { this.romoOptionListDropdown.elem.attr('data-romo-selected-options-list-item-class', this.elem.data('romo-picker-multiple-item-class')); } if (this.elem.data('romo-picker-multiple-max-rows') !== undefined) { this.romoOptionListDropdown.elem.attr('data-romo-selected-options-list-max-rows', this.elem.data('romo-picker-multiple-max-rows')); } this.romoSelectedOptionsList = new RomoSelectedOptionsList(this.romoOptionListDropdown.elem); this.romoSelectedOptionsList.elem.on('romoSelectedOptionsList:itemClick', $.proxy(function(e, itemValue, romoSelectedOptionsList) { var currentValues = this._elemValues(); var index = currentValues.indexOf(itemValue); if (index > -1) { currentValues.splice(index, 1); this._setValuesAndDisplayText(currentValues, ''); } this.romoSelectedOptionsList.doRemoveItem(itemValue); this._refreshUI(); }, this)); this.romoSelectedOptionsList.elem.on('romoSelectedOptionsList:listClick', $.proxy(function(e, romoSelectedOptionsList) { this.romoOptionListDropdown.elem.trigger('dropdown:triggerPopupClose', []); this.romoOptionListDropdown.doFocus(false); }, this)); this.elemWrapper.before(this.romoSelectedOptionsList.elem); this.romoSelectedOptionsList.doRefreshUI(); } } RomoPicker.prototype._bindOptionListDropdown = function() { this.romoOptionListDropdown = this._buildOptionListDropdownElem().romoOptionListDropdown(this.elem)[0]; this.romoOptionListDropdown.elem.on('romoOptionListDropdown:dropdown:toggle', $.proxy(function(e, dropdown, optionListDropdown) { this.elem.trigger('romoPicker:dropdown:toggle', [dropdown, this]); }, this)); this.romoOptionListDropdown.elem.on('romoOptionListDropdown:dropdown:popupOpen', $.proxy(function(e, dropdown, optionListDropdown) { this.elem.trigger('romoPicker:dropdown:popupOpen', [dropdown, this]); }, this)); this.romoOptionListDropdown.elem.on('romoOptionListDropdown:dropdown:popupClose', $.proxy(function(e, dropdown, optionListDropdown) { this.elem.trigger('romoPicker:dropdown:popupClose', [dropdown, this]); }, this)); this.romoOptionListDropdown.elem.on('romoOptionListDropdown:filterChange', $.proxy(function(e, filterValue, romoOptionListDropdown) { if (filterValue !== '') { // immediately update the custom opt as the filter changes // but keep the current filtered option items this._setListItems(this.filteredOptionItems.concat(this._buildCustomOptionItems())); // this will update with the new filtered items plus the custom on ajax callback this.elem.trigger('romoAjax:triggerInvoke', [{ 'filter': filterValue }]); } else { this._setListItems(this.defaultOptionItems.concat(this._buildCustomOptionItems())); } }, this)); this.romoOptionListDropdown.elem.on('romoOptionListDropdown:itemSelected', $.proxy(function(e, itemValue, itemDisplayText, optionListDropdown) { this.romoOptionListDropdown.doFocus(); this.elem.trigger('romoPicker:itemSelected', [itemValue, itemDisplayText, this]); }, this)); this.romoOptionListDropdown.elem.on('romoOptionListDropdown:newItemSelected', $.proxy(function(e, itemValue, itemDisplayText, optionListDropdown) { if (this.romoSelectedOptionsList !== undefined) { var currentValues = this._elemValues(); if (!currentValues.includes(itemValue)) { this._setValuesAndDisplayText(currentValues.concat([itemValue]), ''); this.romoSelectedOptionsList.doAddItem({ 'value': itemValue, 'displayText': itemDisplayText }); } } else { this._setValuesAndDisplayText([itemValue], itemDisplayText); } this._refreshUI(); this.elem.trigger('romoPicker:newItemSelected', [itemValue, itemDisplayText, this]); }, this)); this.romoOptionListDropdown.elem.on('romoOptionListDropdown:change', $.proxy(function(e, newValue, prevValue, optionListDropdown) { this.elem.trigger('change'); this.elem.trigger('romoPicker:change', [newValue, prevValue, this]); }, this)); } RomoPicker.prototype._buildOptionListDropdownElem = function() { var romoOptionListDropdownElem = $('
'); romoOptionListDropdownElem.attr('data-romo-option-list-focus-style-class', 'romo-picker-focus'); romoOptionListDropdownElem.attr('data-romo-dropdown-position', this.elem.data('romo-picker-dropdown-position')); romoOptionListDropdownElem.attr('data-romo-dropdown-style-class', this.elem.data('romo-picker-dropdown-style-class')); romoOptionListDropdownElem.attr('data-romo-dropdown-min-height', this.elem.data('romo-picker-dropdown-min-height')); romoOptionListDropdownElem.attr('data-romo-dropdown-max-height', this.elem.data('romo-picker-dropdown-max-height')); romoOptionListDropdownElem.attr('data-romo-dropdown-height', this.elem.data('romo-picker-dropdown-height')); romoOptionListDropdownElem.attr('data-romo-dropdown-overflow-x', 'hidden'); romoOptionListDropdownElem.attr('data-romo-dropdown-width', 'elem'); if (romoOptionListDropdownElem.data('romo-dropdown-max-height') === undefined) { romoOptionListDropdownElem.attr('data-romo-dropdown-max-height', 'detect'); } if (this.elem.data('romo-picker-filter-placeholder') !== undefined) { romoOptionListDropdownElem.attr('data-romo-option-list-dropdown-filter-placeholder', this.elem.data('romo-picker-filter-placeholder')); } if (this.elem.data('romo-picker-filter-indicator') !== undefined) { romoOptionListDropdownElem.attr('data-romo-option-list-dropdown-filter-indicator', this.elem.data('romo-picker-filter-indicator')); } if (this.elem.data('romo-picker-filter-indicator-width-px') !== undefined) { romoOptionListDropdownElem.attr('data-romo-option-list-filter-indicator-width-px', this.elem.data('romo-picker-filter-indicator-width-px')); } if (this.elem.data('romo-picker-no-filter') !== undefined) { romoOptionListDropdownElem.attr('data-romo-option-list-dropdown-no-filter', this.elem.data('romo-picker-no-filter')); } if (this.elem.data('romo-picker-open-on-focus') !== undefined) { romoOptionListDropdownElem.attr('data-romo-option-list-dropdown-open-on-focus', this.elem.data('romo-picker-open-on-focus')); } var classList = this.elem.attr('class') !== undefined ? this.elem.attr('class').split(/\s+/) : []; $.each(classList, function(idx, classItem) { romoOptionListDropdownElem.addClass(classItem); }); if (this.elem.attr('style') !== undefined) { romoOptionListDropdownElem.attr('style', this.elem.attr('style')); } romoOptionListDropdownElem.css({'width': this.elem.css('width')}); if (this.elem.attr('disabled') !== undefined) { this.romoOptionListDropdown.elem.attr('disabled', this.elem.attr('disabled')); } this.elem.after(romoOptionListDropdownElem); this.elem.hide(); this.elemWrapper = $('
'); if (this.elem.data('romo-picker-btn-group') === true) { this.elemWrapper.addClass('romo-btn-group'); } romoOptionListDropdownElem.before(this.elemWrapper); this.elemWrapper.append(romoOptionListDropdownElem); // the elem wrapper should be treated like a child elem. add it to Romo's // parent-child elems so it will be removed when the elem (picker input) is removed. // delay adding it b/c other components may `append` generated pickers // meaning the picker is removed and then re-added. if added immediately // the "remove" part will incorrectly remove the wrapper. setTimeout($.proxy(function() { Romo.parentChildElems.add(this.elem, [this.elemWrapper]); }, this), 1); this.caretElem = $(); var caretClass = this.elem.data('romo-picker-caret') || this.defaultCaretClass; if (caretClass !== undefined && caretClass !== 'none') { this.caretElem = $(''); this.caretElem.css('line-height', parseInt(Romo.getComputedStyle(romoOptionListDropdownElem[0], "line-height"), 10)+'px'); this.caretElem.on('click', $.proxy(this._onCaretClick, this)); romoOptionListDropdownElem.append(this.caretElem); var caretPaddingPx = this._getCaretPaddingPx(); var caretWidthPx = this._getCaretWidthPx(); var caretPosition = this._getCaretPosition(); // add a pixel to account for the default input border this.caretElem.css(caretPosition, caretPaddingPx+1); // left-side padding // + caret width // + right-side padding var dropdownPaddingPx = caretPaddingPx + caretWidthPx + caretPaddingPx; romoOptionListDropdownElem.css('padding-'+caretPosition, dropdownPaddingPx+'px'); } return romoOptionListDropdownElem; } RomoPicker.prototype._bindAjax = function() { this.elem.attr('data-romo-ajax-disable-default-invoke-on', true); this.elem.attr('data-romo-ajax-url-attr', 'data-romo-picker-url'); this.elem.attr('data-romo-ajax-auto', false); this.elem.on('romoAjax:callStart', $.proxy(function(e, data, romoAjax) { this.romoOptionListDropdown.elem.trigger('romoOptionListDropdown:triggerFilterIndicatorStart', []); }, this)); this.elem.on('romoAjax:callSuccess', $.proxy(function(e, data, romoAjax) { this.filteredOptionItems = data; this._setListItems(this.filteredOptionItems.concat(this._buildCustomOptionItems())); this.romoOptionListDropdown.elem.trigger('romoOptionListDropdown:triggerFilterIndicatorStop', []); }, this)); this.elem.on('romoAjax:callError', $.proxy(function(e, xhr, romoAjax) { this._setListItems(this.defaultOptionItems.concat(this._buildCustomOptionItems())); this.romoOptionListDropdown.elem.trigger('romoOptionListDropdown:triggerFilterIndicatorStop', []); }, this)); this.elem.romoAjax(); } RomoPicker.prototype._setListItems = function(items) { this.romoOptionListDropdown.doSetListItems(items); this.romoOptionListDropdown.elem.trigger('romoOptionListDropdown:triggerListOptionsUpdate', [this.romoOptionListDropdown.optItemElems().first()]); } RomoPicker.prototype._buildDefaultOptionItems = function() { var items = [] if (this.elem.data('romo-picker-empty-option') === true) { items.push({ 'type': 'option', 'value': '', 'displayText': (this.elem.data('romo-picker-empty-option-display-text') || ''), 'displayHtml': ' ' }); } return items; } RomoPicker.prototype._buildCustomOptionItems = function() { var items = []; var value = this.romoOptionListDropdown.optionFilterValue(); if (value !== '' && this.elem.data('romo-picker-custom-option') === true) { var prompt = this.elem.data('romo-picker-custom-option-prompt'); if (prompt !== undefined) { items.push({ 'type': 'optgroup', 'label': prompt, 'items': [this._buildCustomOptionItem(value)] }); } else { items.push(this._buildCustomOptionItem(value)); } } return items; } RomoPicker.prototype._buildCustomOptionItem = function(value) { return { 'type': 'option', 'value': value, 'displayText': value, 'displayHtml': value }; } RomoPicker.prototype._setValuesAndDisplayText = function(newValues, displayText) { this.elem[0].value = newValues.join(this._elemValuesDelim()); // store the display text on the DOM to compliment the value being stored on the // DOM via the elem above. need to use `attr` to persist selected values to the // DOM for back button logic to work. using `data` won't persist changes to DOM // and breaks how the component deals with back-button behavior. this.elem.attr('data-romo-picker-display-text', displayText); } RomoPicker.prototype._elemValues = function() { return this.elem[0].value.split(this._elemValuesDelim()).filter(function(v){ return v !== ''; }); } RomoPicker.prototype._elemValuesDelim = function() { return this.elem.data('romo-picker-values-delim') || this.defaultValuesDelim; } RomoPicker.prototype._refreshUI = function() { // need to use `attr` so it will always read from the DOM // using `data` works the first time but does some elem caching or something // so it won't work subsequent times. var text = this.elem.attr('data-romo-picker-display-text'); if (this.romoSelectedOptionsList !== undefined) { this.romoSelectedOptionsList.doRefreshUI(); } if (text === '') { text = ' ' } this.romoOptionListDropdown.elem.find('.romo-picker-text').html(text); } RomoPicker.prototype._onCaretClick = function(e) { if (this.elem.prop('disabled') === false) { this.romoOptionListDropdown.doFocus(); this.elem.trigger('romoPicker:triggerPopupOpen'); } } RomoPicker.prototype._getCaretPaddingPx = function() { return ( this.elem.data('romo-picker-caret-padding-px') || this.defaultCaretPaddingPx ); } RomoPicker.prototype._getCaretWidthPx = function() { return ( this.elem.data('romo-picker-caret-width-px') || parseInt(Romo.getComputedStyle(this.caretElem[0], "width"), 10) ); } RomoPicker.prototype._getCaretPosition = function() { return ( this.elem.data('romo-picker-caret-position') || this.defaultCaretPosition ); } Romo.onInitUI(function(e) { Romo.initUIElems(e, '[data-romo-picker-auto="true"]').romoPicker(); });