////////////////////////// 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);
}
}
};