'use strict'; /*@ Ox.Editable Editable element () -> Input Element (options) -> Input Element (options, self) -> Input Element options Options object editing If true, loads in editing state format Format function (value) -> Formatted value value Input value self Shared private variable @*/ Ox.Editable = function(options, self) { self = self || {}; var that = Ox.Element({ element: options.type == 'textarea' ? '
' : '', tooltip: options.tooltip }, self) .defaults({ clickLink: null, editable: true, editing: false, format: null, height: 0, placeholder: '', submitOnBlur: true, tooltip: '', value: '', width: 0, type: 'input' }) .options(options || {}) .addClass('OxEditableElement') .bind({ click: function() { return false; } }) .bindEvent({ doubleclick: edit, singleclick: function(e) { if ($(e.target).is('a')) { if (self.options.clickLink) { self.options.clickLink(e); } else { document.location.href = $(e.target).attr('href'); } } } }); self.options.value = self.options.value.toString(); self.css = {}; self.$value = Ox.Element(self.options.type == 'input' ? '' : '
') .addClass('OxValue') //.css({background: 'red'}) .html(formatValue()) //[self.options.editing ? 'hide' : 'show']() .appendTo(that); if (self.options.editing) { // edit will toggle self.options.editing self.options.editing = false; edit(); } function blur() { that.triggerEvent('blur'); } function cancel() { self.options.value = self.originalValue; self.$input.value(formatInputValue()).hide(); self.$test.html(formatTestValue()); self.$value.html(formatValue()).show(); 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.width(), '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 edit() { 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() .appendTo(that.$element); self.$input = Ox.Input({ changeOnKeypress: true, element: self.options.type == 'input' ? '' : '
', style: 'square', type: self.options.type, value: formatInputValue(), }) .css(self.css) .bindEvent({ cancel: cancel, change: change, submit: submit }) .appendTo(that.$element); self.$input.bindEvent({ blur: self.options.submitOnBlur ? submit : blur }); 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' }); } // 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'); } } function formatInputValue() { return Ox.decodeHTML( self.options.type == 'input' ? self.options.value : self.options.value.replace(//g, '\n\n') ); } function formatTestValue() { return self.options.type == 'input' ? self.options.value.replace(/ /g, ' ') : Ox.parseHTML(self.options.value || ' ') .replace(/$/, '
 '); } function formatValue() { 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) } return value; } function submit() { self.options.editing = false; self.options.value = Ox.parseHTML(self.$input.value()); self.$input.value(formatInputValue()).hide(); self.$test.html(formatTestValue()); self.$value.html(formatValue()).show(); that.$tooltip && that.$tooltip.options({title: self.options.tooltip}); that.triggerEvent('submit', { value: self.options.value }); } self.setOption = function(key, value) { if (key == 'editing') { if (value) { // edit will toggle self.options.editing self.options.editing = false; edit(); } else { submit(); } } else if (key == 'height' || key == 'width') { var css = {}; css[key] = value + 'px'; self.$test && self.$test.css(css); self.$input && self.$input.css(css); self.$input && self.$input.find(self.options.type).css(css); } }; that.css = function(css) { self.css = css; that.$element.css(css); self.$value.css(css); self.$test && self.$test.css(css); self.$input && self.$input.css(css); return that; }; return that; };