////////////////////////// DropDown /////////////////////////// /** * A drop down selector * @constructor */ hui.ui.DropDown = function(options) { this.options = hui.override({ placeholder: null, url: null, source: null, focus: false }, options); this.name = options.name; var e = this.element = hui.get(options.element); this.items = options.items || []; this.index = -1; this.value = hui.isDefined(this.options.value) ? this.options.value : null; this.dirty = true; this.busy = false; hui.ui.extend(this); if (options.listener) { this.listen(options.listener); } this._attach(); this._updateIndex(); this._updateUI(); if (this.options.url) { this.options.source = new hui.ui.Source({ url: this.options.url, delegate: this }); } else if (this.options.source) { this.options.source.listen(this); } }; hui.ui.DropDown.create = function(options) { options = options || {}; var cls = 'hui_dropdown'; if (options.variant) { cls += ' hui_dropdown-' + options.variant; } options.element = hui.build('a', { 'class': cls, href: '#', html: '<span class="hui_dropdown_text"></span>' }); var drop = new hui.ui.DropDown(options); if (options.items) { drop.setItems(options.items); } return drop; }; hui.ui.DropDown.prototype = { nodes: { text: '.hui_dropdown_text' }, _attach: function() { hui.listen(this.element, 'click', this._click.bind(this)); hui.listen(this.element, 'blur', this._hideSelector.bind(this)); hui.listen(this.element, 'keydown', this._keyDown.bind(this)); if (!this.options.focus) { hui.listen(this.element, 'mousedown', function(e) { hui.stop(e); }); } }, _updateIndex: function() { this.index = -1; for (var i = 0; i < this.items.length; i++) { if (this.items[i].value == this.value) { this.index = i; } } }, _updateUI: function() { var selected = this.items[this.index]; this.nodes.text.innerHTML = ''; if (selected) { var text = selected.label || selected.title || selected.text || ''; hui.dom.addText(this.nodes.text, text); } else if (this.options.placeholder) { this.nodes.text.appendChild(hui.build('span', { 'class': 'hui_dropdown_placeholder', text: hui.string.escape(this.options.placeholder) })); } if (!this.selector) { return; } var as = hui.findAll('.hui_dropdown_option', this.selector); for (var i = 0; i < as.length; i++) { hui.cls.set(as[i], 'hui_selected', this.index == i); } }, _click: function(e) { if (this.busy) { return; } hui.stop(e); if (this._selectorVisible) { this._hideSelector(); //this.element.blur(); } else { this._showSelector(); this._hider = function(e) { e = hui.event(e); if (!e.isDescendantOf(this.element)) { this._hideSelector(); } }.bind(this); hui.listen(document.body, 'mousedown', this._hider); } }, _showSelector: function() { this._buildSelector(); var el = this.element, s = this.selector; if (this.options.focus) { el.focus(); } if (!this.items) return; var docHeight = hui.window.getViewHeight(); if (docHeight < 200) { var left = hui.position.getLeft(this.element); hui.style.set(this.selector, { 'left': left + 'px', top: '5px' }); } else { var windowScrollTop = hui.window.getScrollTop(); var scrollOffsetTop = hui.position.getScrollOffset(this.element).top; var scrollTop = windowScrollTop - scrollOffsetTop; hui.position.place({ target: { element: this.element, vertical: 1, horizontal: 0 }, source: { element: this.selector, vertical: 0, horizontal: 0 }, top: scrollTop }); } hui.style.set(s, { visibility: 'hidden', display: 'block', width: '' }); var height = Math.min(docHeight - hui.position.getTop(s) - 5, 200); var width = Math.max(el.clientWidth - 5, 100, s.clientWidth + 20); var space = hui.window.getViewWidth() - hui.position.getLeft(el) - 20; width = Math.min(width, space); hui.style.set(s, { visibility: 'visible', width: width + 'px', zIndex: hui.ui.nextTopIndex(), maxHeight: height + 'px' }); this._selectorVisible = true; }, _hideSelector: function() { hui.unListen(document.body, 'mousedown', this._hider); if (!this.selector) { return; } this.selector.style.display = 'none'; this._selectorVisible = false; }, _keyDown: function(e) { if (this.busy) { return; } if (this.items.length === 0) { return; } if (e.keyCode == 40) { hui.stop(e); if (this.index >= this.items.length - 1) { this.value = this.items[0].value; } else { this.value = this.items[this.index + 1].value; } this._updateIndex(); this._updateUI(); this._fireChange(); } else if (e.keyCode == 38) { hui.stop(e); if (this.index > 0) { this.index--; } else { this.index = this.items.length - 1; } this.value = this.items[this.index].value; this._updateUI(); this._fireChange(); } }, selectFirst: function() { if (this.items.length > 0) { this.setValue(this.items[0].value); } }, /** Get the value of the selected item */ getValue: function() { return this.value; }, setValue: function(value) { this.value = value; this._updateIndex(); this._updateUI(); }, /** Set the value to null */ reset: function() { this.setValue(null); }, /** Refresh the associated source */ refresh: function() { if (this.options.source) { this.options.source.refresh(); } }, stress: function() { hui.ui.stress(this); }, focus: function() { try { this.element.focus(); } catch (ignore) {} }, // TODO: Is this used? getItem: function() { if (this.index >= 0) { return this.items[this.index]; } return 0; }, addItem: function(item) { this.items.push(item); this.dirty = true; this._updateIndex(); this._updateUI(); }, setItems: function(items) { this.items = items; this.dirty = true; this.index = -1; this._updateIndex(); this._updateUI(); }, /** @private */ $optionsLoaded: function(items) { this.setItems(items); }, /** @private */ $sourceIsBusy: function() { this.busy = true; hui.style.setOpacity(this.element, 0.5); }, /** @private */ $sourceIsNotBusy: function() { this.busy = false; hui.style.setOpacity(this.element, 1); }, /** @private */ $sourceShouldRefresh: function() { return hui.dom.isVisible(this.element); }, /** @private */ $visibilityChanged: function() { if (hui.dom.isVisible(this.element)) { if (this.options.source) { // If there is a source, make sure it is initially this.options.source.refreshFirst(); } } else { this._hideSelector(); } }, _buildSelector: function() { if (!this.dirty || !this.items) { return; } if (!this.selector) { this.selector = hui.build('div', { 'class': 'hui_dropdown_options' }); document.body.appendChild(this.selector); hui.listen(this.selector, 'mousedown', function(e) { hui.stop(e); }); } else { this.selector.innerHTML = ''; } var self = this; hui.each(this.items, function(item, i) { var e = hui.build('span', { 'class': 'hui_dropdown_option', text: item.label || item.title || item.text || '' }); hui.listen(e, 'mousedown', function(e) { hui.stop(e); self._itemClicked(item, i); hui.listenOnce(document.body, 'mouseup', function(e) { hui.stop(e); }); }); if (i == self.index) { hui.cls.add(e, 'hui_selected'); } self.selector.appendChild(e); }); this.dirty = false; }, _itemClicked: function(item, index) { this.index = index; var changed = this.value != this.items[index].value; this.value = this.items[index].value; this._updateUI(); this._hideSelector(); if (changed) { this._fireChange(); } }, _fireChange: function() { hui.ui.callAncestors(this, 'childValueChanged', this.value); this.fire('valueChanged', this.value); hui.ui.firePropertyChange(this, 'value', this.value); }, detach: function() { if (this.selector) { hui.dom.remove(this.selector); } } };