/** */ Ext.define("Terrasoft.controls.InlineTextEdit", { alternateClassName: "Terrasoft.InlineTextEdit", extend: "Terrasoft.BaseEdit", //region Properties: Protected /** * CKEditor instance. * @protected * @type {CKEDITOR.editor} */ editor: null, /** * Css-class for control when validation is failed. * @protected * @type {String} */ errorClass: "inline-text-edit-error", /** * Name of css-class for placeholder. * @protected * @type {String} */ placeholderClassName: "inline-text-edit-placeholder", /* * @inheritdoc Terrasoft.controls.component#styles * @override */ styles: { wrapStyles: null, elStyles: null, validationStyle: null }, /* * @inheritdoc Terrasoft.controls.component#classes * @override */ classes: { wrapClasses: ["inline-text-edit-wrap"], elClasses: ["inline-text-edit-el"], validationClasses: ["inline-text-edit-validation"] }, /** * Template of control. * @protected * @override * @type {String[]} */ tpl: [ /*jshint quotmark:false */ '<div id="{id}-inline-text-edit-wrap" style="{wrapStyles}" class="{wrapClasses}"' + ' data-placeholder="{placeholder}">', '<div tabindex="0" id="{id}-inline-text-edit-el" style="{elStyles}" class="{elClasses}" ' + 'contenteditable = "{canEdit}">', '{value}', '</div>', '<span id="{id}-validation" class="{validationClasses}" style="{validationStyle}">', '{validationText}', '</span>', '</div>' /*jshint quotmark:double */ ], /** * Selected text. * @protected * @override * @type {String[]} */ selectedText: null, /** * CKEditor config that enables all features (data will not be filtered). * @protected * @type {Object} */ ckeditorDefaultConfig: { allowedContent: true }, //endregion //region Methods: Protected /** * @inheritdoc Terrasoft.BaseEdit#init * @override */ init: function () { this.callParent(arguments); this.addEvents( * @event macrobuttonclicked * Calls when macros button is clicked. */ "macrobuttonclicked", /** * @event selectedtextchanged * Calls when selected text is changed. */ "selectedtextchanged", /** * @event selectedtextchanged * @deprecated Deprecated event because event name contains Cyrillic character. * Calls when selected text is changed. */ "selectedtextсhanged"); }, /** * @inheritdoc Terrasoft.BaseEdit#onEnterKeyPressed * @override */ onEnterKeyPressed: Terrasoft.emptyFn, /** * Handles selected text change. * @protected */ onSelectionChange: function () { var selection = this.editor.getSelection(); var selectedText = selection.getSelectedText(); this.updateSelectedText(selectedText); }, /** * Ckeditor contentDom event handler. Subscribes editor click and keyup events. * @protected */ onContentDom: function () { var el = this.el; el.on("click", this.onSelectionChange, this); el.on("keyup", this.onSelectionChange, this); }, /** * Handles macros button click. * @protected * @param {Object} event Event info object. */ onMacroButtonClicked: function (event) { this.fireEvent("macrobuttonclicked", this, event.data); }, /** * Updates selected text. * @protected * @param {String} selectedText Selected text. */ updateSelectedText: function (selectedText) { if (selectedText !== this.selectedText) { this.selectedText = selectedText; this.fireEvent("selectedtextсhanged", this.selectedText, this); this.fireEvent("selectedtextchanged", this.selectedText, this); } }, /** * Initializes an instance of CKEditor. * @protected */ initInlineEditor: function () { if (this.el) { var editor = this.editor = CKEDITOR.inline(this.el.id, this.ckeditorDefaultConfig); editor.on("contentDom", this.onContentDom, this); this.initEditor(); this.initExtraPluginsToolbar(); } }, /** * Inits extra plugin toolbar items. * @protected */ initExtraPluginsToolbar: function () { this.createButton("bpmonlinemacros", this.onMacroButtonClicked); }, /** * Creates additional button for ckeditor. * @protected * @param {String} pluginName Ckeditor plugin name. * @param {Function} onClick New button click event handler. * @param {Array} [items=null] Ckeditor items. */ createButton: function (pluginName, onClick, items) { var clickEvent = pluginName + "click"; items = items || [pluginName]; this.editor.on(clickEvent, onClick, this); var config = this.editor.config; config.toolbar.push({ name: pluginName, items: items }); config.toolbarGroups.push({ name: pluginName }); config.extraPlugins += "," + pluginName; }, /** * Inits ckeditor. * @private */ initEditor: function () { var editorConfig = this.editor.config; editorConfig.toolbar = []; editorConfig.toolbarGroups = []; editorConfig.extraPlugins = ""; }, /** * Destroys an instance of CKEditor. * @protected */ destroyInlineEditor: function () { if (this.editor) { if (this.editor.loaded) { this.editor.destroy(); } else { var editor = CKEDITOR.instances[this.editor.name]; editor.on("loaded", function () { this.destroy(); }, editor); } this.editor = null; } }, /** * @inheritdoc Terrasoft.BaseEdit#getTplData * @protected * @override */ getTplData: function () { var tplData = this.callParent(arguments); var placeholder = Terrasoft.encodeHtml(this.placeholder); Ext.apply(tplData, { canEdit: !this.readonly, value: this.value, placeholder: placeholder }); if (Ext.isEmpty(this.value)) { tplData.wrapClasses = [this.placeholderClassName]; } if (!this.validationInfo.isValid) { tplData.wrapClasses.push(this.errorClass); } return tplData; }, /** * @inheritdoc Terrasoft.BaseEdit#combineSelectors * @protected * @override */ combineSelectors: function () { return { wrapEl: "#" + this.id + "-inline-text-edit-wrap", el: "#" + this.id + "-inline-text-edit-el", validationEl: "#" + this.id + "-validation" }; }, /** * Initializes a subscribtion to the DOM events. * @override * @protected */ initDomEvents: function () { this.callParent(arguments); if (this.el) { this.el.on({ "focus": { fn: this.onFocus, scope: this }, "blur": { fn: this.onBlur, scope: this } }); } var validationInfo = this.validationInfo; if (!validationInfo.isValid) { this.showValidationMessage(validationInfo.invalidMessage); } }, /** * @inheritdoc Terrasoft.BaseEdit#clearDomListeners * @override */ clearDomListeners: function () { this.callParent(arguments); if (this.el) { this.el.un("click", this.onSelectionChange, this); this.el.un("keyup", this.onSelectionChange, this); } }, /** * @inheritdoc Terrasoft.BaseEdit#getBindConfig * @protected * @override */ getBindConfig: function () { var bindConfig = this.callParent(arguments); Ext.apply(bindConfig, { selectedText: { changeEvent: "selectedtextchanged", deprecatedChangeEvent: "selectedtextсhanged", changeMethod: "setSelectedText" } }); return bindConfig; }, /** * Adds CSS class for control depending on isValid flag. If isValid is setted to true, class is added, * otherwise class is removed. * @protected */ setMarkOut: function () { if (this.rendered && this.validationEl) { var validationMessage = ""; if (!this.validationInfo.isValid) { this.wrapEl.addCls(this.errorClass); validationMessage = this.validationInfo.invalidMessage; this.validationEl.setStyle("width", ""); var wrapWidth = this.wrapEl.getWidth(); var validationElWidth = this.validationEl.getWidth(); if (validationElWidth > wrapWidth) { this.validationEl.setWidth(wrapWidth); } } else { this.wrapEl.removeCls(this.errorClass); } this.showValidationMessage(validationMessage); this.validationEl.setVisible(!this.validationInfo.isValid); } }, /** * Updates control's value. * @protected * @param {String} value Value of control. */ updateValue: function (value) { var result = false; if (this.value !== value) { this.value = value; this.fireEvent("change", this); result = true; } return result; }, /** * Checks if editor content is empty. * @protected * @return {Boolean} If editor content is empty returns true, otherwise false. */ isEditorDataEmpty: function () { var editorData = this.editor.getData(); return Ext.isEmpty(editorData); }, /** * Sets placeholder visibility. * @protected * @param {Boolean } visible Indicates whether placeholder is visible. */ setPlaceholderVisible: function (visible) { if (visible) { this.wrapEl.addCls(this.placeholderClassName); } else { this.wrapEl.removeCls(this.placeholderClassName); } }, /** * Handles focus control event. * @protected */ onFocus: function () { if (this.rendered && !this.focused) { if (this.isEditorDataEmpty()) { this.setPlaceholderVisible(false); } this.focused = true; } }, /** * Handles blur control event. * When handles blur event updates control's value and sets placeholder visibility. * @protected */ onBlur: function () { if (this.rendered) { this.focused = false; if (this.isEditorDataEmpty()) { this.setPlaceholderVisible(true); } var editorData = this.editor.getData(); this.updateValue(editorData); this.fireEvent("blur", this); } }, /** * @inheritdoc Terrasoft.Component#onAfterRender * @override */ onAfterRender: function () { this.callParent(arguments); this.destroyInlineEditor(); this.initInlineEditor(); }, /** * @inheritdoc Terrasoft.Component#onAfterRender * @override */ onAfterReRender: function () { this.callParent(arguments); this.destroyInlineEditor(); this.initInlineEditor(); }, /** * @inheritdoc Terrasoft.Component#onDestroy * @override */ onDestroy: function () { this.destroyInlineEditor(); this.callParent(arguments); }, //endregion //region Methods: Public /** * Sets control's value. * If control is rendered calls reRender. * @param {String} value */ setValue: function (value) { if (this.updateValue(value) && this.rendered) { this.reRender(); } }, /** * Sets readonly-mode. * @param {Boolean} readonly If readonly is setted to true, turns on readonly-mode, otherwise turns it off. */ setReadonly: function (readonly) { if (this.readonly !== readonly) { this.readonly = readonly; if (this.rendered) { this.reRender(); } } }, /** * Sets placeholder's value. * @param {String} placeholder Text that is visible when editor content is empty. */ setPlaceholder: function (placeholder) { if (this.placeholder !== placeholder) { this.placeholder = placeholder; if (this.rendered) { this.reRender(); } } }, /** * Inserts value to content. * @protected * @param {String} value Inserting value. */ insertContent: function (value) { this.editor.insertText(value); }, /** * Sets value of selected text. * @param {String} value Selected text. */ setSelectedText: function (value) { if (value !== this.selectedText && this.editor) { var editor = this.editor; var selection = editor.getSelection(); var selectedText = selection && selection.getSelectedText(); if (!Ext.isEmpty(selectedText)) { var range = selection.getRanges()[0]; range.deleteContents(); } this.insertContent(value); this.updateSelectedText(value); var editorData = this.editor.getData(); this.updateValue(editorData); var isDataEmpty = this.isEditorDataEmpty(); this.setPlaceholderVisible(isDataEmpty); } } //endregion });