'use strict'; /*@ Ox.ArrayEditable Array Editable Object @*/ Ox.ArrayEditable = function(options, self) { self = self || {}; var that = Ox.Element(options.editable === false ? {} : { tooltip: 'Doubleclick to add ' + (options.itemName || 'item') }, self) .defaults({ editable: true, itemName: 'item', items: [], position: -1, selected: '', sort: [], submitOnBlur: true, type: 'input', width: 256 }) .options(options || {}) .addClass('OxArrayEditable OxArrayEditable' + Ox.toTitleCase(self.options.type)) .css({width: self.options.width - 8 + 'px'}) // 2 x 4 px padding .bindEvent({ anyclick: anyclick, doubleclick: doubleclick, key_delete: deleteItem, key_enter: function() { that.editItem(); }, key_escape: selectNone, key_down: self.options.type == 'input' ? selectLast : selectNext, key_left: self.options.type == 'input' ? selectPrevious : selectFirst, key_right: self.options.type == 'input' ? selectNext : selectLast, key_up: self.options.type == 'input' ? selectFirst : selectPrevious }); self.$items = []; renderItems(); self.selected = getSelectedPosition(); function anyclick(e) { var $target = $(e.target), $parent = $target.parent(), position = $parent.data('position'); //ignore clicks while editing if (!$target.is('.OxInput')) { if (self.selected > -1) { //end editing but keep selected if clicked next to a keyword if (self.editing || self.$items[self.selected].options('editing')) { self.editing = false; self.$items[self.selected].options({editing: false}); //deselect if not editing and not going to select antoher one } else if (!$parent.is('.OxEditableElement')) { selectNone(); } } //select if clicked on other editable element if ($parent.is('.OxEditableElement')) { selectItem( e.metaKey && position == self.selected ? '' : $parent.data('position') ); } that.gainFocus(); } } function deleteItem() { if (self.options.editable) { self.options.items.splice(self.selected, 1); renderItems(); that.triggerEvent('delete', { id: self.options.selected }); } } function doubleclick(e) { var $target = $(e.target), $parent = $target.parent(); if ($parent.is('.OxEditableElement')) { that.editItem(); } else if (!$target.is('.OxInput')) { that.triggerEvent('add'); } } function getSelectedId() { return self.selected > -1 ? self.options.items[self.selected].id : ''; } function getSelectedPosition() { return Ox.getIndexById(self.options.items, self.options.selected); } function renderItems() { that.empty(); sortItems(); self.options.items.forEach(function(item, i) { i && self.options.type == 'input' && $('') .html(', ') .appendTo(that); self.$items[i] = Ox.Editable({ editable: self.options.editable && item.editable, format: function(value) { return value || ' ' }, submitOnBlur: self.options.submitOnBlur, tooltip: 'Click to select' + ( item.editable ? ', doubleclick to edit' : '' ), type: self.options.type, value: item.value, width: self.options.type == 'input' ? 0 : self.options.width - 8 }) .addClass(item.id == self.options.selected ? 'OxSelected' : '') .data({position: i}) .bindEvent({ blur: function(data) { that.gainFocus(); that.triggerEvent('blur', data); }, cancel: function(data) { that.gainFocus(); Ox.print("GAINING FOCUS!") that.triggerEvent('blur', data); }, edit: function(data) { self.editing = true; that.triggerEvent('edit', data); }, submit: function(data) { that.gainFocus(); submitItem(i, data.value); } }) .appendTo(that); }); } function selectFirst() { self.selected > -1 && selectItem(0); } function selectItem(idOrPosition) { if (Ox.isString(idOrPosition)) { self.options.selected = idOrPosition; self.selected = getSelectedPosition(); } else { self.selected = idOrPosition; self.options.selected = getSelectedId(); } if (self.options.selected == '' && self.editing) { self.editing = false; that.blurItem(); } Ox.print('SELECT ITEM', self.options.selected, self.selected); that.find('.OxSelected').removeClass('OxSelected'); self.selected > -1 && self.$items[self.selected].addClass('OxSelected'); triggerSelectEvent(); } function selectLast() { self.selected > -1 && selectItem(self.options.items.length - 1); } function selectNext() { self.selected > -1 && self.selected < self.options.items.length - 1 && selectItem(self.selected + 1); } function selectNone() { selectItem(-1); } function selectPrevious() { self.selected > 0 && selectItem(self.selected - 1); } function sortItems() { if (!Ox.isEmpty(self.options.sort)) { self.options.items = Ox.sortBy(self.options.items, self.options.sort); self.selected = getSelectedPosition(); } } function submitItem(position, value) { var item = self.options.items[position]; if (value === '') { deleteItem(); } else if (item.value === value) { that.triggerEvent('blur'); } else { that.triggerEvent('submit', { id: item.id, value: value }); item.value = value; } } function triggerSelectEvent() { if (!self.triggered) { that.triggerEvent('select', Ox.extend({ id: self.options.selected }, self.options.selected ? { top: self.$items[self.selected].offset().top } : {})); self.triggered = true; setTimeout(function() { self.triggered = false; }, 250); } } self.setOption = function(key, value) { if (key == 'items') { renderItems(); } else if (key == 'selected') { selectItem(value); } else if (key == 'sort') { renderItems(); } else if (key == 'width') { that.css({width: value - 8 + 'px'}); // 2 x 4 px padding self.options.type == 'textarea' && self.$items.forEach(function($item) { $item.options({width: value}) }); } } that.addItem = function(position, item) { if (self.options.editable) { self.options.items.splice(position, 0, item); renderItems(); } //that.triggerEvent('add'); /* self.values = Ox.filter(values, function(value) { return value; }); self.values.push(''); renderItems(); Ox.last(self.$items).triggerEvent('doubleclick'); */ }; that.blurItem = function() { if (self.options.selected) { self.$items[self.selected].options({editing: false}); } else { self.$items.forEach(function($item) { $item.options({editing: false}); }); } }; that.editItem = function() { if (self.options.editable && self.options.selected) { Ox.forEach(self.$items, function($item) { if ($item.data('position') == self.selected) { Ox.print('DBLCLICK') $item.triggerEvent('doubleclick'); return false; } }); } }; that.reloadItems = function() { renderItems(); }; that.removeItem = function(position) { if (self.options.editable) { } }; return that; };