/** * NativeListBox.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ (function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, undef; /** * This class is used to create list boxes/select list. This one will generate * a native control the way that the browser produces them by default. * * @class tinymce.ui.NativeListBox * @extends tinymce.ui.ListBox */ tinymce.create('tinymce.ui.NativeListBox:tinymce.ui.ListBox', { /** * Constructs a new button control instance. * * @constructor * @method NativeListBox * @param {String} id Button control id for the button. * @param {Object} s Optional name/value settings object. */ NativeListBox : function(id, s) { this.parent(id, s); this.classPrefix = 'mceNativeListBox'; }, /** * Sets the disabled state for the control. This will add CSS classes to the * element that contains the control. So that it can be disabled visually. * * @method setDisabled * @param {Boolean} s Boolean state if the control should be disabled or not. */ setDisabled : function(s) { DOM.get(this.id).disabled = s; this.setAriaProperty('disabled', s); }, /** * Returns true/false if the control is disabled or not. This is a method since you can then * choose to check some class or some internal bool state in subclasses. * * @method isDisabled * @return {Boolean} true/false if the control is disabled or not. */ isDisabled : function() { return DOM.get(this.id).disabled; }, /** * Selects a item/option by value. This will both add a visual selection to the * item and change the title of the control to the title of the option. * * @method select * @param {String/function} va Value to look for inside the list box or a function selector. */ select : function(va) { var t = this, fv, f; if (va == undef) return t.selectByIndex(-1); // Is string or number make function selector if (va && typeof(va)=="function") f = va; else { f = function(v) { return v == va; }; } // Do we need to do something? if (va != t.selectedValue) { // Find item each(t.items, function(o, i) { if (f(o.value)) { fv = 1; t.selectByIndex(i); return false; } }); if (!fv) t.selectByIndex(-1); } }, /** * Selects a item/option by index. This will both add a visual selection to the * item and change the title of the control to the title of the option. * * @method selectByIndex * @param {String} idx Index to select, pass -1 to select menu/title of select box. */ selectByIndex : function(idx) { DOM.get(this.id).selectedIndex = idx + 1; this.selectedValue = this.items[idx] ? this.items[idx].value : null; }, /** * Adds a option item to the list box. * * @method add * @param {String} n Title for the new option. * @param {String} v Value for the new option. * @param {Object} o Optional object with settings like for example class. */ add : function(n, v, a) { var o, t = this; a = a || {}; a.value = v; if (t.isRendered()) DOM.add(DOM.get(this.id), 'option', a, n); o = { title : n, value : v, attribs : a }; t.items.push(o); t.onAdd.dispatch(t, o); }, /** * Executes the specified callback function for the menu item. In this case when the user clicks the menu item. * * @method getLength */ getLength : function() { return this.items.length; }, /** * Renders the list box as a HTML string. This method is much faster than using the DOM and when * creating a whole toolbar with buttons it does make a lot of difference. * * @method renderHTML * @return {String} HTML for the list box control element. */ renderHTML : function() { var h, t = this; h = DOM.createHTML('option', {value : ''}, '-- ' + t.settings.title + ' --'); each(t.items, function(it) { h += DOM.createHTML('option', {value : it.value}, it.title); }); h = DOM.createHTML('select', {id : t.id, 'class' : 'mceNativeListBox', 'aria-labelledby': t.id + '_aria'}, h); h += DOM.createHTML('span', {id : t.id + '_aria', 'style': 'display: none'}, t.settings.title); return h; }, /** * Post render handler. This function will be called after the UI has been * rendered so that events can be added. * * @method postRender */ postRender : function() { var t = this, ch, changeListenerAdded = true; t.rendered = true; function onChange(e) { var v = t.items[e.target.selectedIndex - 1]; if (v && (v = v.value)) { t.onChange.dispatch(t, v); if (t.settings.onselect) t.settings.onselect(v); } }; Event.add(t.id, 'change', onChange); // Accessibility keyhandler Event.add(t.id, 'keydown', function(e) { var bf, DOM_VK_LEFT = 37, DOM_VK_RIGHT = 39, DOM_VK_UP = 38, DOM_VK_DOWN = 40, DOM_VK_RETURN = 13, DOM_VK_SPACE = 32; Event.remove(t.id, 'change', ch); changeListenerAdded = false; bf = Event.add(t.id, 'blur', function() { if (changeListenerAdded) return; changeListenerAdded = true; Event.add(t.id, 'change', onChange); Event.remove(t.id, 'blur', bf); }); if (e.keyCode == DOM_VK_RETURN || e.keyCode == DOM_VK_SPACE) { onChange(e); return Event.cancel(e); } else if (e.keyCode == DOM_VK_DOWN || e.keyCode == DOM_VK_UP) { // allow native implementation (navigate select element options) e.stopImmediatePropagation(); } }); t.onPostRender.dispatch(t, DOM.get(t.id)); } }); })(tinymce);