/* editor.js is part of Aloha Editor project http://aloha-editor.org * * Aloha Editor is a WYSIWYG HTML5 inline editing library and editor. * Copyright (c) 2010-2012 Gentics Software GmbH, Vienna, Austria. * Contributors http://aloha-editor.org/contribution.php * * Aloha Editor is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * Aloha Editor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * As an additional permission to the GNU GPL version 2, you may distribute * non-source (e.g., minimized or compacted) forms of the Aloha-Editor * source code without the copy of the GNU GPL normally required, * provided you include this license notice and a URL through which * recipients can access the Corresponding Source. */ /** * @name block.editor * @namespace Block attribute editors */ define(['jquery', 'aloha/observable', 'util/class'], function(jQuery, Observable, Class) { "use strict"; /** * This is the base class for all editors in the sidebar. You need to extend * this class if you need to write your own editor. In most cases, however, * it is sufficent to subclass the AbstractFormElementEditor. * * @name block.editor.AbstractEditor * @class An abstract editor */ var AbstractEditor = Class.extend(Observable, /** @lends block.editor.AbstractEditor */ { /** * Schema of the current element * * @param {Object} * @api */ schema: null, /** * @constructor */ _constructor: function(schema) { this.schema = schema; }, /** * Template method to render the editor elements. Override it * in your subclass! Needs to return the jQuery element which * should be added to the DOM * * @return {jQuery} * @api */ render: function() { // Implement in subclass! }, /** * Template method to get the current editor value * * Override it in your subclass! * * @return {String} * @api */ getValue: function() { // Implement in subclass! }, /** * Method which is called at initialization time, to set the current value. * * Override it in your subclass! * * You should not throw any change event here, as we need to break the loop "Block" -> "Editor" -> "Block" * * @param {String} value * @api */ setValue: function(value) { // Implement in subclass! }, /** * Destroy the editor elements and unbind events * @api */ destroy: function() { // Implement in subclass! }, /** * On deactivating, we still need to trigger a change event if the value has been modified. * * @private */ _deactivate: function() { this.trigger('change', this.getValue()); this.destroy(); } }); /** * This is a more specialized FormElementEditor which should be used * for form-based editors. * * @name block.editor.AbstractFormElementEditor * @class An abstract form editor with label * @extends block.editor.AbstractEditor */ var AbstractFormElementEditor = AbstractEditor.extend( /** @lends block.editor.AbstractFormElementEditor */ { /** * Input element HTML definition * * You need to override this in your subclass. * * @type String * * @api */ formInputElementDefinition: null, /** * The jQuery element of the form input element. * * @type {jQuery} */ _$formInputElement: null, /** * Render the label and form element * @return {jQuery} */ render: function() { var $wrapper = jQuery('
'); var guid = GENTICS.Utils.guid(); $wrapper.append(this.renderLabel().attr('id', guid)); $wrapper.append(this.renderFormElement().attr('id', guid)); return $wrapper; }, /** * Render the label for the editor, by using the "label" property * from the schema. * * @return {jQuery} */ renderLabel: function() { var element = jQuery(''); element.html(this.schema.label); return element; }, /** * Render the form input element * @return {jQuery} */ renderFormElement: function() { var that = this; this._$formInputElement = jQuery(this.formInputElementDefinition); this.afterRenderFormElement(this._$formInputElement); this._$formInputElement.change(function() { that.trigger('change', that.getValue()); }); return this._$formInputElement; }, /** * Callback which can be implemented by subclasses to adjust the rendered * form input element * * @param {jQuery} $formElement the form element being rendered * @api */ afterRenderFormElement: function($formElement) { }, /** * @return {String} */ getValue: function() { return this._$formInputElement.val(); }, /** * We do not throw any change event here, as we need to break the loop "Block" -> "Editor" -> "Block" */ setValue: function(value) { this._$formInputElement.val(value); }, /** * Cleanup and remove the input element */ destroy: function() { this._$formInputElement.remove(); } }); /** * @name block.editor.StringEditor * @class An editor for string input * @extends block.editor.AbstractFormElementEditor */ var StringEditor = AbstractFormElementEditor.extend( /** @lends block.editor.StringEditor */ { formInputElementDefinition: '' }); /** * @name block.editor.NumberEditor * @class An editor for numbers * @extends block.editor.AbstractFormElementEditor */ var NumberEditor = AbstractFormElementEditor.extend( /** @lends block.editor.NumberEditor */ { // TODO Range should be an option formInputElementDefinition: '', afterRenderFormElement: function($formElement) { if (!this.schema.range) return; if (this.schema.range.min) { $formElement.attr('min', this.schema.range.min); } if (this.schema.range.max) { $formElement.attr('max', this.schema.range.max); } if (this.schema.range.step) { $formElement.attr('step', this.schema.range.step); } } }); /** * @name block.editor.UrlEditor * @class An editor for URLs * @extends block.editor.AbstractFormElementEditor */ var UrlEditor = AbstractFormElementEditor.extend( /** @lends block.editor.UrlEditor */ { formInputElementDefinition: '' }); /** * @name block.editor.EmailEditor * @class An editor for email addresses * @extends block.editor.AbstractFormElementEditor */ var EmailEditor = AbstractFormElementEditor.extend( /** @lends block.editor.EmailEditor */ { formInputElementDefinition: '' }); /** * @name block.editor.SelectEditor * @class An editor for select fields * @extends block.editor.AbstractFormElementEditor */ var SelectEditor = AbstractFormElementEditor.extend( /** @lends block.editor.SelectEditor */ { formInputElementDefinition: '', afterRenderFormElement: function($formElement) { jQuery.each(this.schema.values, function() { var el = this; $formElement.append(jQuery('').attr('value', el.key).html(el.label)); }); } }); /** * @name block.editor.ButtonEditor * @class An editor for buttons, executing a custom supplied callback "callback" * @extends block.editor.AbstractFormElementEditor */ var ButtonEditor = AbstractFormElementEditor.extend( /** @lends block.editor.SelectEditor */ { formInputElementDefinition: '', afterRenderFormElement: function($formElement) { var that = this; $formElement.html(this.schema.buttonLabel); $formElement.click(function() { that.schema.callback(); }) } }); return { AbstractEditor: AbstractEditor, AbstractFormElementEditor: AbstractFormElementEditor, StringEditor: StringEditor, NumberEditor: NumberEditor, UrlEditor: UrlEditor, EmailEditor: EmailEditor, SelectEditor: SelectEditor, ButtonEditor: ButtonEditor } });