'use strict'; /*@ Ox.Select <f> Select Object ([options[, self]) -> <o:Ox.Element> Select Object click <!> Click event change <!> Change event options <o> Options object disabled <b|false> If true, select is disabled id <s> Element id items <a|[]> Items (array of {id, title} or strings) label <s|''> Label labelWidth <n|64> Label width max <n|1> Maximum number of selected items maxWidth <n|0> Maximum menu width min <n|1> Minimum number of selected items overlap <s|'none'> Can be 'none', 'left' or 'right' selectable <b|true> is selectable size <s|'medium'> Size, can be small, medium, large style <s|'rounded'> Style ('rounded' or 'square') title <s|''> Select title tooltip <s|f|''> Tooltip title, or function that returns one (e) -> <string> Tooltip title e <object> Mouse event type <s|'text'> Type ('text' or 'image') value <a|s> Selected id, or array of selected ids width <s|n|'auto'> Width in px, or 'auto' self <o> Shared private variable @*/ Ox.Select = function(options, self) { self = self || {}; var that = Ox.Element({ tooltip: options.tooltip || '' }, self) .defaults({ id: '', items: [], label: '', labelWidth: 64, max: 1, maxWidth: 0, min: 1, overlap: 'none', size: 'medium', style: 'rounded', title: '', type: 'text', value: options.max != 1 ? [] : '', width: 'auto' }) // fixme: make default selection restorable .options(options) .update({ labelWidth: function() { self.$label.options({width: self.options.labelWidth}); self.$title.css({width: getTitleWidth() + 'px'}); }, title: function() { if (self.options.type == 'text') { self.$title.html(self.options.title); } else { self.$button.options({title: self.options.title}); } }, width: function() { that.css({width: self.options.width- 2 + 'px'}); self.$title.css({width: getTitleWidth() + 'px'}); }, value: function() { var value = self.options.value; if (self.options.type == 'text' && !self.options.title) { self.$title.html(getItem(value).title); } value !== '' && Ox.makeArray(value).forEach(function(value) { self.$menu.checkItem(value); }); self.options.value = self.optionGroup.value(); } }) .addClass( 'OxSelect Ox' + Ox.toTitleCase(self.options.size) + ' Ox' + Ox.toTitleCase(self.options.style) + ( self.options.overlap == 'none' ? '' : ' OxOverlap' + Ox.toTitleCase(self.options.overlap) ) + (self.options.label ? ' OxLabelSelect' : '') ) .css(self.options.width == 'auto' ? {} : { width: self.options.width - 2 + 'px' }) .bindEvent({ anyclick: showMenu, key_escape: loseFocus, key_down: showMenu }); self.options.items = self.options.items.map(function(item) { var isObject = Ox.isObject(item); return Ox.isEmpty(item) ? item : { id: isObject ? item.id : item, title: isObject ? item.title : item, checked: Ox.makeArray(self.options.value).indexOf( isObject ? item.id : item ) > -1, disabled: isObject ? item.disabled : false }; }); self.optionGroup = new Ox.OptionGroup( self.options.items, self.options.min, self.options.max, 'checked' ); self.options.items = self.optionGroup.init(); self.options.value = self.optionGroup.value(); if (self.options.label) { self.$label = Ox.Label({ overlap: 'right', textAlign: 'right', title: self.options.label, width: self.options.labelWidth }) .appendTo(that); } if (self.options.type == 'text') { self.$title = $('<div>') .addClass('OxTitle') .css({ width: getTitleWidth() + 'px' }) .html( self.options.title || getItem(self.options.value).title ) .appendTo(that); } self.$button = Ox.Button({ id: self.options.id + 'Button', style: 'symbol', title: self.options.type == 'text' || !self.options.title ? 'select' : self.options.title, type: 'image' }) .appendTo(that); self.$menu = Ox.Menu({ element: self.$title || self.$button, id: self.options.id + 'Menu', items: [{ group: self.options.id + 'Group', items: self.options.items, max: self.options.max, min: self.options.min }], maxWidth: self.options.maxWidth, side: 'bottom', // FIXME: should be edge size: self.options.size }) .bindEvent({ change: changeMenu, click: clickMenu, hide: hideMenu }); self.options.type == 'image' && self.$menu.addClass('OxRight'); function clickMenu(data) { that.triggerEvent('click', data); } function changeMenu(data) { self.options.value = self.optionGroup.value(); self.$title && self.$title.html( self.options.title || getItem(self.options.value).title ); that.triggerEvent('change', { title: Ox.isEmpty(self.options.value) ? '' : Ox.isArray(self.options.value) ? self.options.value.map(function(value) { return getItem(value).title; }) : getItem(self.options.value).title, value: self.options.value }); } function getItem(id) { return Ox.getObjectById(self.options.items, id); } function getTitleWidth() { // fixme: used to be 22. obscure return self.options.width - 24 - ( self.options.label ? self.options.labelWidth : 0 ); } function hideMenu() { that.loseFocus(); that.removeClass('OxSelected'); } function loseFocus() { that.loseFocus(); } function selectItem() { } function showMenu() { that.gainFocus(); that.addClass('OxSelected'); self.options.tooltip && that.$tooltip.hide(); self.$menu.showMenu(); } /*@ disableItem <f> disableItem @*/ that.disableItem = function(id) { self.$menu.getItem(id).options({disabled: true}); }; /*@ enableItem <f> enableItem @*/ that.enableItem = function(id) { self.$menu.getItem(id).options({disabled: false}); }; /*@ remove <f> remove @*/ self.superRemove = that.remove; that.remove = function() { self.$menu.remove(); self.superRemove(); }; /*@ selected <f> gets selected item () -> <o> returns array of selected items with id and title @*/ that.selected = function() { return Ox.makeArray(self.optionGroup.value()).map(function(id) { return { id: id, title: getItem(id).title }; }); }; /* that.width = function(val) { // fixme: silly hack, and won't work for css() ... remove! that.$element.width(val + 16); that.$button.width(val); //that.$symbol.width(val); return that; }; */ return that; };