Ox.EditableContent = function(options, self) { self = self || {}; var that = Ox.Element({ element: options.type == 'div' ? '
' : '', tooltip: options.tooltip }, self) .defaults({ clickLink: null, editable: true, placeholder: '', tooltip: '', type: 'span', value: '' }) .options(options || {}) .update({ highlight: function() { !self.editing && self.$value.html(formatValue()); }, value: function() { !self.editing && self.$value.html(formatValue()); } }) .addClass('OxEditableContent') .on({ click: function(e) { var $target = $(e.target); if (!e.shiftKey && ($target.is('a') || ($target = $target.parents('a')).length)) { e.preventDefault(); if (self.options.clickLink) { e.target = $target[0]; self.options.clickLink(e); } else { document.location.href = $target.attr('href'); } } return false; } }) .bindEvent({ doubleclick: edit }); self.options.value = self.options.value.toString(); self.editing = false; self.$value = Ox.Element(self.options.type == 'span' ? '' : '
') .html(formatValue(self.options.value)) .on({ blur: submit, keydown: function(e) { if (self.editing) { if (self.options.type == 'span' && e.keyCode == 13) { submit(); return false; } else if (e.keyCode == 27) { cancel(); return false; } } } }) .appendTo(that); function cancel() { if (self.editing) { that.loseFocus(); self.editing = false; self.$value .attr({contenteditable: false}) .removeClass('OxEditableContentInput') .html(formatValue()); that.triggerEvent('cancel', {value: self.options.value}); } } function edit() { if (self.options.editable && !self.editing) { self.$value .text(formatInputValue() || ' ') .addClass('OxEditableContentInput') .attr({contenteditable: true}); self.editing = true; that.gainFocus(); setTimeout(updateSelection, 50); } } function formatInputValue() { return Ox.decodeHTMLEntities( self.options.type == 'span' ? self.options.value : self.options.value.replace(//g, '\n\n') ); } 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); } if (self.options.highlight) { value = Ox.highlight( value, self.options.highlight, 'OxHighlight', true ); } return value; } function parseValue() { var value = Ox.clean( self.$value.text().replace(/\n\n+/g, '\0') ).replace(/\0/g, '\n\n').trim(); return ( self.options.type == 'span' ? Ox.encodeHTMLEntities(value) : Ox.sanitizeHTML(value, self.options.tags, self.options.replaceTags) ); } function setCSS() { } function submit() { if (self.editing) { that.loseFocus(); self.editing = false; self.options.value = self.$value.text(); if (self.options.value.charCodeAt(0) == 160) { self.options.value = ''; } self.$value .attr({contenteditable: false}) .removeClass('OxEditableContentInput') .html(formatValue()); that.triggerEvent('submit', {value: self.options.value}); } } function updateSelection() { var range, selection; self.$value[0].focus(); selection = window.getSelection(); selection.removeAllRanges(); range = document.createRange(); range.selectNodeContents(self.$value[0]); selection.addRange(range); if (self.options.type != 'span') { setTimeout(function() { selection.collapseToEnd(); }, 0); } } that.css = function(css) { that.$element.css(css); self.$value.css(css); return that; } return that; };