diff --git a/source/Ox.UI/css/Ox.UI.css b/source/Ox.UI/css/Ox.UI.css index 7f8f93a0..779be344 100644 --- a/source/Ox.UI/css/Ox.UI.css +++ b/source/Ox.UI/css/Ox.UI.css @@ -631,6 +631,9 @@ OxArrayEditable padding: 4px; border-top: 1px solid rgb(128, 128, 128); } +.OxArrayEditable.OxArrayEditableTextarea textarea { + padding: 4px; +} .OxArrayEditable.OxArrayEditableTextarea .OxEditableElement:first-child { border-top: 0px } diff --git a/source/Ox.UI/js/Form/Ox.ArrayEditable.js b/source/Ox.UI/js/Form/Ox.ArrayEditable.js index 8c49747c..39254ea0 100644 --- a/source/Ox.UI/js/Form/Ox.ArrayEditable.js +++ b/source/Ox.UI/js/Form/Ox.ArrayEditable.js @@ -14,8 +14,11 @@ Ox.ArrayEditable = function(options, self) { editable: true, itemName: 'item', items: [], + maxHeight: void 0, + placeholder: '', position: -1, selected: '', + separator: ',', sort: [], submitOnBlur: true, type: 'input', @@ -23,7 +26,7 @@ Ox.ArrayEditable = function(options, self) { }) .options(options || {}) .addClass('OxArrayEditable OxArrayEditable' + Ox.toTitleCase(self.options.type)) - .css({width: self.options.width - 8 + 'px'}) // 2 x 4 px padding + .css({width: self.options.width - (self.options.type == 'input' ? 8 : 0) + 'px'}) // 2 x 4 px padding .bindEvent({ anyclick: anyclick, doubleclick: doubleclick, @@ -39,33 +42,35 @@ Ox.ArrayEditable = function(options, self) { }); self.$items = []; + self.editing = false; renderItems(); self.selected = getSelectedPosition(); function anyclick(e) { + Ox.print('SELF EDITING', self.editing) 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 + Ox.print('BLURRED EDITING', self.blurred, self.editing) if ($parent.is('.OxEditableElement')) { + // select another item + Ox.print('AAAAA') selectItem( e.metaKey && position == self.selected ? '' : $parent.data('position') ); + } else if (!self.blurred) { + // if there wasn't an active input element + if (self.editing) { + // blur if still in editing mode + that.blurItem(); + } else { + // othewise deselect selected + selectNone(); + } } that.gainFocus(); } @@ -78,6 +83,8 @@ Ox.ArrayEditable = function(options, self) { that.triggerEvent('delete', { id: self.options.selected }); + self.selected = -1; + self.options.selected = ''; } } @@ -99,50 +106,87 @@ Ox.ArrayEditable = function(options, self) { return Ox.getIndexById(self.options.items, self.options.selected); } - function renderItems() { + function renderItems(blur) { + if (self.editing) { + self.options.items[getSelectedPosition()].value = that.find(self.options.type + ':visible').val(); + } that.empty(); - sortItems(); - self.options.items.forEach(function(item, i) { - i && self.options.type == 'input' - && $('') - .html(', ') + if (self.options.items.length == 0) { + Ox.Editable({ + editable: false, + type: 'text', + value: self.options.placeholder + }) + .addClass('OxPlaceholder') + .appendTo(that); + } else { + sortItems(); + self.options.items.forEach(function(item, i) { + if (i && self.options.type == 'input') { + $('') + .addClass('OxSeparator') + .html(self.options.separator + ' ') + .appendTo(that); + } + self.$items[i] = Ox.Editable({ + blurred: self.editing && i == self.selected ? blur : false, + editable: self.options.editable && item.editable, + editing: self.editing && i == self.selected, + /* + format: function(value) { + return value || ' ' + }, + */ + maxHeight: self.options.maxHeight, + 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 - 9 + }) + .addClass(item.id == self.options.selected ? 'OxSelected' : '') + //.css(self.options.type == 'textarea' ? {padding: '4px'} : {}) + .data({position: i}) + .bindEvent({ + blur: function(data) { + // fixme: remove data + that.gainFocus(); + that.triggerEvent('blur', { + id: item.id, + value: data.value + }); + self.blurred = true; + setTimeout(function() { + self.blurred = false; + }, 250); + }, + cancel: function(data) { + self.editing = false; + that.gainFocus(); + that.triggerEvent('blur', data); + }, + change: function(data) { + that.triggerEvent('change', { + id: item.id, + value: data.value + }); + }, + edit: function(data) { + self.editing = true; + that.triggerEvent('edit', data); + }, + submit: function(data) { + self.editing = false; + that.gainFocus(); + submitItem(i, data.value); + } + }) .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); - }); + }); + } + //self.editing && that.editItem(blur); } function selectFirst() { @@ -150,7 +194,6 @@ Ox.ArrayEditable = function(options, self) { } function selectItem(idOrPosition) { - Ox.print('???????', self.editing) if (Ox.isString(idOrPosition)) { self.options.selected = idOrPosition; self.selected = getSelectedPosition(); @@ -197,10 +240,8 @@ Ox.ArrayEditable = function(options, self) { var item = self.options.items[position]; if (value === '') { deleteItem(); - } else if (item.value === value) { - that.triggerEvent('blur'); } else { - that.triggerEvent('submit', { + that.triggerEvent(item.value === value ? 'blur' : 'submit', { id: item.id, value: value }); @@ -224,7 +265,7 @@ Ox.ArrayEditable = function(options, self) { self.setOption = function(key, value) { if (key == 'items') { - renderItems(); + renderItems(true); } else if (key == 'selected') { selectItem(value); } else if (key == 'sort') { @@ -242,6 +283,7 @@ Ox.ArrayEditable = function(options, self) { self.options.items.splice(position, 0, item); renderItems(); } + return that; //that.triggerEvent('add'); /* self.values = Ox.filter(values, function(value) { @@ -259,34 +301,44 @@ Ox.ArrayEditable = function(options, self) { self.$items[self.selected].options({editing: false}); } else { */ - self.$items.forEach(function($item) { - $item.options({editing: false}); - }); + self.editing = false; + self.$items.forEach(function($item) { + $item.options({editing: false}); + }); //} + return that; }; that.editItem = function() { + Ox.print('AE EDIT ITEM') 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; - } - }); + self.editing = true; + self.$items[self.selected].options({editing: true}); } + return that; }; that.reloadItems = function() { renderItems(); + return that; }; that.removeItem = function(position) { if (self.options.editable) { } + return that; }; + /* + that.submitItem = function() { + if (self.editing) { + self.editing = false; + self.$items[self.selected].options({editing: false}); + } + } + */ + return that; }; diff --git a/source/Ox.UI/js/Form/Ox.Editable.js b/source/Ox.UI/js/Form/Ox.Editable.js index 1f100eb9..9afc2df5 100644 --- a/source/Ox.UI/js/Form/Ox.Editable.js +++ b/source/Ox.UI/js/Form/Ox.Editable.js @@ -19,11 +19,13 @@ Ox.Editable = function(options, self) { tooltip: options.tooltip }, self) .defaults({ + blurred: false, clickLink: null, editable: true, editing: false, format: null, height: 0, + maxHeight: void 0, placeholder: '', submitOnBlur: true, tooltip: '', @@ -62,13 +64,22 @@ Ox.Editable = function(options, self) { .appendTo(that); if (self.options.editing) { - // edit will toggle self.options.editing - self.options.editing = false; - edit(); + // need timeout so that when determining height + // the element is actually in the DOM + setTimeout(function() { + // edit will toggle self.options.editing + self.options.editing = false; + edit(); + }, 0); } - function blur() { - that.triggerEvent('blur'); + function blur(data) { + self.options.value = parseValue(); + if (self.options.value !== self.originalValue) { + self.originalValue = self.options.value; + that.triggerEvent('change', {value: self.options.value}); + } + that.triggerEvent('blur', data); } function cancel() { @@ -80,55 +91,29 @@ Ox.Editable = function(options, self) { that.triggerEvent('cancel', {value: self.options.value}); } - function change(event) { - var height, width; - self.options.value = event.value; - self.$value.html(formatValue()); - self.$test.html(formatTestValue()); - //height = self.options.height || Ox.limit(self.$test.height() + 2, self.minHeight, self.maxHeight); - height = self.options.height || Math.max(self.$test.height() + 2, self.minHeight); - width = self.options.width || Ox.limit(self.$test.width() + 2, self.minWidth, self.maxWidth); - Ox.Log('Form', self.options.width, self.$test.html(), self.$test.width(), self.$test.height(), 'wxh', width, height) - if (self.options.type == 'input') { - self.$input.options({ - width: width - }); - self.$input.find('input').css({width: width + 'px'}); - } else { - self.$input.options({ - height: height, - width: width - }); - self.$input.find('textarea').css({ - height: height + 'px', - width: width + 'px' - }); - } - /* - that.triggerEvent('change', { - value: event.value - }); - */ + function change(data) { + setTimeout(function() { + var height, width; + self.options.value = data.value; + self.$value.html(formatValue()); + self.$test.html(formatTestValue()); + setSizes(); + }, 25); } function edit() { + Ox.print('E EDIT! editable editing', self.options.editable, self.options.editing) var height, width; if (self.options.editable && !self.options.editing) { self.options.editing = true; self.originalValue = self.options.value; - self.minWidth = 8; - self.maxWidth = that.parent().width(); - self.minHeight = 14; - self.maxHeight = that.parent().height(); - height = self.options.height || self.$value.height(); - width = self.options.width || self.$value.width(); self.$value.hide(); Ox.Log('Form', 'H:::', self.options.height, height) if (!self.$test) { self.$test = self.$value.$element.clone() .css(Ox.extend({display: 'inline-block'}, self.css)) .html(formatTestValue()) - .hide() + .css({background: 'rgb(192, 192, 192)'}) .appendTo(that.$element); self.$input = Ox.Input({ changeOnKeypress: true, @@ -149,29 +134,23 @@ Ox.Editable = function(options, self) { }); self.$input.find('input').css(self.css); } - self.$input.options({ - width: width, - height: height - }) - .show(); - if (self.options.type == 'input') { - self.$input.find('input').css({ - height: height + 'px', - width: width + 'px' - }); - } else { - self.$input.find('textarea').css({ - height: height + 'px', - width: width + 'px' - }); + self.minWidth = 8; + self.maxWidth = that.parent().width(); + self.minHeight = 13; + self.maxHeight = self.options.type == 'input' + ? self.minHeight + : self.options.maxHeight || that.parent().height(); + setSizes(); + self.$input.show(); + if (!self.options.blurred) { + setTimeout(function() { + self.$input.focusInput(self.options.type == 'input'); + }, 0); + that.$tooltip && that.$tooltip.options({title: ''}); + that.triggerEvent('edit'); } - // fixme: why can't this be chained? - setTimeout(function() { - self.$input.focusInput(self.options.type == 'input'); - }, 0); - that.$tooltip && that.$tooltip.options({title: ''}); - that.triggerEvent('edit'); } + self.options.blurred = false; } function formatInputValue() { @@ -184,7 +163,7 @@ Ox.Editable = function(options, self) { function formatTestValue() { return self.options.type == 'input' - ? self.options.value.replace(/ /g, ' ') + ? Ox.encodeHTML(self.options.value) //.replace(/ /g, ' ') : Ox.encodeHTML(self.options.value || ' ') .replace(/\n$/, '\n ') .replace(/\n/g, '
') @@ -195,18 +174,46 @@ Ox.Editable = function(options, self) { } function formatValue() { + Ox.print('HUH?', self.options.value, self.options.format); var value = self.options.value; if (self.options.value === '' && self.options.placeholder) { value = self.options.placeholder; } else if (self.options.format) { value = self.options.format(self.options.value) + } else if (self.options.type == 'input') { + Ox.print('HELLO??') + value = Ox.encodeHTML(self.options.value); } return value; } + function parseValue() { + return self.options.type == 'input' + ? Ox.encodeHTML(self.$input.value()) + : Ox.parseHTML(self.$input.value()); + } + + function setSizes() { + var height, width; + self.$test.show(); + height = self.options.height || Ox.limit(self.$test.height(), self.minHeight, self.maxHeight); + width = self.options.width || Ox.limit(self.$test.width(), self.minWidth, self.maxWidth); + Ox.print('stH', self.$test.height(), self.options.value) + self.$test.hide(); + self.$input.options({ + width: width, + height: height + }) + //.show(); + self.$input.find(self.options.type).css({ + height: height + 'px', + width: width + 'px' + }); + } + function submit() { self.options.editing = false; - self.options.value = Ox.parseHTML(self.$input.value()); + //self.options.value = parseValue(); self.$input.value(formatInputValue()).hide(); self.$test.html(formatTestValue()); self.$value.html(formatValue()).show(); diff --git a/source/Ox.UI/js/Form/Ox.Input.js b/source/Ox.UI/js/Form/Ox.Input.js index eb41df4c..92733ea7 100644 --- a/source/Ox.UI/js/Form/Ox.Input.js +++ b/source/Ox.UI/js/Form/Ox.Input.js @@ -114,13 +114,12 @@ Ox.Input = function(options, self) { height: self.options.height + 'px' } : {}) ) - .bindEvent(Ox.extend(self.options.type == 'textarea' ? { - key_shift_enter: submit - } : { + .bindEvent(Ox.extend(self.options.type == 'input' ? { key_enter: submit - }, { + } : {}, { key_control_v: paste, - key_escape: cancel + key_escape: cancel, + key_shift_enter: submit })); if ( @@ -1942,5 +1941,3 @@ Ox.Range_ = function(options, self) { return that; }; - -