UNPKG

silk-gui

Version:

GUI for developers and Node OS

180 lines (163 loc) 4.06 kB
var _ = require('../../util') var Watcher = require('../../watcher') var dirParser = require('../../parsers/directive') module.exports = { bind: function () { var self = this var el = this.el // check options param var optionsParam = this._checkParam('options') if (optionsParam) { initOptions.call(this, optionsParam) } this.number = this._checkParam('number') != null this.multiple = el.hasAttribute('multiple') this.listener = function () { var value = self.multiple ? getMultiValue(el) : el.value value = self.number ? _.isArray(value) ? value.map(_.toNumber) : _.toNumber(value) : value self.set(value, true) } _.on(el, 'change', this.listener) checkInitialValue.call(this) }, update: function (value) { /* jshint eqeqeq: false */ var el = this.el el.selectedIndex = -1 var multi = this.multiple && _.isArray(value) var options = el.options var i = options.length var option while (i--) { option = options[i] option.selected = multi ? indexOf(value, option.value) > -1 : value == option.value } }, unbind: function () { _.off(this.el, 'change', this.listener) if (this.optionWatcher) { this.optionWatcher.teardown() } } } /** * Initialize the option list from the param. * * @param {String} expression */ function initOptions (expression) { var self = this var descriptor = dirParser.parse(expression)[0] function optionUpdateWatcher (value) { if (_.isArray(value)) { self.el.innerHTML = '' buildOptions(self.el, value) if (self._watcher) { self.update(self._watcher.value) } } else { _.warn('Invalid options value for v-model: ' + value) } } this.optionWatcher = new Watcher( this.vm, descriptor.expression, optionUpdateWatcher, { deep: true, filters: _.resolveFilters(this.vm, descriptor.filters) } ) // update with initial value optionUpdateWatcher(this.optionWatcher.value) } /** * Build up option elements. IE9 doesn't create options * when setting innerHTML on <select> elements, so we have * to use DOM API here. * * @param {Element} parent - a <select> or an <optgroup> * @param {Array} options */ function buildOptions (parent, options) { var op, el for (var i = 0, l = options.length; i < l; i++) { op = options[i] if (!op.options) { el = document.createElement('option') if (typeof op === 'string') { el.text = el.value = op } else { el.text = op.text el.value = op.value } } else { el = document.createElement('optgroup') el.label = op.label buildOptions(el, op.options) } parent.appendChild(el) } } /** * Check the initial value for selected options. */ function checkInitialValue () { var initValue var options = this.el.options for (var i = 0, l = options.length; i < l; i++) { if (options[i].hasAttribute('selected')) { if (this.multiple) { (initValue || (initValue = [])) .push(options[i].value) } else { initValue = options[i].value } } } if (typeof initValue !== 'undefined') { this._initValue = this.number ? _.toNumber(initValue) : initValue } } /** * Helper to extract a value array for select[multiple] * * @param {SelectElement} el * @return {Array} */ function getMultiValue (el) { return Array.prototype.filter .call(el.options, filterSelected) .map(getOptionValue) } function filterSelected (op) { return op.selected } function getOptionValue (op) { return op.value || op.text } /** * Native Array.indexOf uses strict equal, but in this * case we need to match string/numbers with soft equal. * * @param {Array} arr * @param {*} val */ function indexOf (arr, val) { /* jshint eqeqeq: false */ var i = arr.length while (i--) { if (arr[i] == val) return i } return -1 }