UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

515 lines (512 loc) • 20.5 kB
/** * DevExtreme (ui/html_editor/ui.html_editor.js) * Version: 20.1.7 * Build date: Tue Aug 25 2020 * * Copyright (c) 2012 - 2020 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var _renderer = require("../../core/renderer"); var _renderer2 = _interopRequireDefault(_renderer); var _extend = require("../../core/utils/extend"); var _type = require("../../core/utils/type"); var _dom = require("../../core/utils/dom"); var _common = require("../../core/utils/common"); var _component_registrator = require("../../core/component_registrator"); var _component_registrator2 = _interopRequireDefault(_component_registrator); var _empty_template = require("../../core/templates/empty_template"); var _editor = require("../editor/editor"); var _editor2 = _interopRequireDefault(_editor); var _ui = require("../widget/ui.errors"); var _ui2 = _interopRequireDefault(_ui); var _callbacks = require("../../core/utils/callbacks"); var _callbacks2 = _interopRequireDefault(_callbacks); var _deferred = require("../../core/utils/deferred"); var _events_engine = require("../../events/core/events_engine"); var _events_engine2 = _interopRequireDefault(_events_engine); var _utils = require("../../events/utils"); var _uiEventsEmitterGesture = require("../scroll_view/ui.events.emitter.gesture.scroll"); var _uiEventsEmitterGesture2 = _interopRequireDefault(_uiEventsEmitterGesture); var _utils2 = require("../text_box/utils.scroll"); var _quill_registrator = require("./quill_registrator"); var _quill_registrator2 = _interopRequireDefault(_quill_registrator); require("./converters/delta"); var _converterController = require("./converterController"); var _converterController2 = _interopRequireDefault(_converterController); var _wordLists = require("./matchers/wordLists"); var _wordLists2 = _interopRequireDefault(_wordLists); var _textDecoration = require("./matchers/textDecoration"); var _textDecoration2 = _interopRequireDefault(_textDecoration); var _newLine = require("./matchers/newLine"); var _newLine2 = _interopRequireDefault(_newLine); var _formDialog = require("./ui/formDialog"); var _formDialog2 = _interopRequireDefault(_formDialog); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj } } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }) } else { obj[key] = value } return obj } var HTML_EDITOR_CLASS = "dx-htmleditor"; var QUILL_CONTAINER_CLASS = "dx-quill-container"; var QUILL_CLIPBOARD_CLASS = "ql-clipboard"; var HTML_EDITOR_SUBMIT_ELEMENT_CLASS = "dx-htmleditor-submit-element"; var HTML_EDITOR_CONTENT_CLASS = "dx-htmleditor-content"; var MARKDOWN_VALUE_TYPE = "markdown"; var ANONYMOUS_TEMPLATE_NAME = "htmlContent"; var ELEMENT_NODE = 1; var TEXT_NODE = 3; var HtmlEditor = _editor2.default.inherit({ _getDefaultOptions: function() { return (0, _extend.extend)(this.callBase(), { focusStateEnabled: true, valueType: "html", placeholder: "", toolbar: null, variables: null, mediaResizing: null, mentions: null, customizeModules: null, formDialogOptions: null }) }, _init: function() { this.callBase(); this._cleanCallback = (0, _callbacks2.default)(); this._contentInitializedCallback = (0, _callbacks2.default)() }, _getAnonymousTemplateName: function() { return ANONYMOUS_TEMPLATE_NAME }, _initTemplates: function() { this._templateManager.addDefaultTemplates(_defineProperty({}, ANONYMOUS_TEMPLATE_NAME, new _empty_template.EmptyTemplate)); this.callBase() }, _focusTarget: function() { return this._getContent() }, _getContent: function() { return this.$element().find(".".concat(HTML_EDITOR_CONTENT_CLASS)) }, _focusInHandler: function(_ref) { var relatedTarget = _ref.relatedTarget; if (this._shouldSkipFocusEvent(relatedTarget)) { return } this._toggleFocusClass(true, this.$element()); this.callBase.apply(this, arguments) }, _focusOutHandler: function(_ref2) { var relatedTarget = _ref2.relatedTarget; if (this._shouldSkipFocusEvent(relatedTarget)) { return } this._toggleFocusClass(false, this.$element()); this.callBase.apply(this, arguments) }, _shouldSkipFocusEvent: function(relatedTarget) { return (0, _renderer2.default)(relatedTarget).hasClass(QUILL_CLIPBOARD_CLASS) }, _initMarkup: function() { this._$htmlContainer = (0, _renderer2.default)("<div>").addClass(QUILL_CONTAINER_CLASS); this.$element().addClass(HTML_EDITOR_CLASS).wrapInner(this._$htmlContainer); var template = this._getTemplate(ANONYMOUS_TEMPLATE_NAME); var transclude = true; this._$templateResult = template && template.render({ container: (0, _dom.getPublicElement)(this._$htmlContainer), noModel: true, transclude: transclude }); this._renderSubmitElement(); this.callBase(); this._updateContainerMarkup() }, _renderSubmitElement: function() { this._$submitElement = (0, _renderer2.default)("<textarea>").addClass(HTML_EDITOR_SUBMIT_ELEMENT_CLASS).attr("hidden", true).appendTo(this.$element()); this._setSubmitValue(this.option("value")) }, _setSubmitValue: function(value) { this._getSubmitElement().val(value) }, _getSubmitElement: function() { return this._$submitElement }, _updateContainerMarkup: function() { var markup = this.option("value"); if (this._isMarkdownValue()) { this._prepareMarkdownConverter(); markup = this._markdownConverter.toHtml(markup) } if (markup) { this._$htmlContainer.html(markup) } }, _prepareMarkdownConverter: function() { var MarkdownConverter = _converterController2.default.getConverter("markdown"); if (MarkdownConverter) { this._markdownConverter = new MarkdownConverter } else { throw _ui2.default.Error("E1051", "markdown") } }, _render: function() { this._prepareConverters(); this.callBase() }, _prepareQuillRegistrator: function() { if (!this._quillRegistrator) { this._quillRegistrator = new _quill_registrator2.default } }, _getRegistrator: function() { this._prepareQuillRegistrator(); return this._quillRegistrator }, _prepareConverters: function() { if (!this._deltaConverter) { var DeltaConverter = _converterController2.default.getConverter("delta"); if (DeltaConverter) { this._deltaConverter = new DeltaConverter } } if (this.option("valueType") === MARKDOWN_VALUE_TYPE && !this._markdownConverter) { this._prepareMarkdownConverter() } }, _renderContentImpl: function() { this._contentRenderedDeferred = new _deferred.Deferred; var renderContentPromise = this._contentRenderedDeferred.promise(); this.callBase(); this._renderHtmlEditor(); this._renderFormDialog(); this._addKeyPressHandler(); return renderContentPromise }, _addKeyPressHandler: function() { var keyDownEvent = (0, _utils.addNamespace)("keydown", "".concat(this.NAME, "TextChange")); _events_engine2.default.on(this._$htmlContainer, keyDownEvent, this._keyDownHandler.bind(this)) }, _keyDownHandler: function(e) { this._saveValueChangeEvent(e) }, _renderHtmlEditor: function() { var _this = this; var customizeModules = this.option("customizeModules"); var modulesConfig = this._getModulesConfig(); if ((0, _type.isFunction)(customizeModules)) { customizeModules(modulesConfig) } this._quillInstance = this._getRegistrator().createEditor(this._$htmlContainer[0], { placeholder: this.option("placeholder"), readOnly: this.option("readOnly") || this.option("disabled"), modules: modulesConfig, theme: "basic" }); this._deltaConverter.setQuillInstance(this._quillInstance); this._textChangeHandlerWithContext = this._textChangeHandler.bind(this); this._quillInstance.on("text-change", this._textChangeHandlerWithContext); this._renderScrollHandler(); if (this._hasTranscludedContent()) { this._updateContentTask = (0, _common.executeAsync)(function() { _this._applyTranscludedContent() }) } else { this._finalizeContentRendering() } }, _renderScrollHandler: function() { var $scrollContainer = this._getContent(); var initScrollData = (0, _utils2.prepareScrollData)($scrollContainer); _events_engine2.default.on($scrollContainer, (0, _utils.addNamespace)(_uiEventsEmitterGesture2.default.init, this.NAME), initScrollData, _common.noop) }, _applyTranscludedContent: function() { var valueOption = this.option("value"); if (!(0, _type.isDefined)(valueOption)) { var markup = this._deltaConverter.toHtml(); var newDelta = this._quillInstance.clipboard.convert(markup); if (newDelta.ops.length) { this._quillInstance.setContents(newDelta); return } } this._finalizeContentRendering() }, _hasTranscludedContent: function() { return this._$templateResult && this._$templateResult.length }, _getModulesConfig: function() { var quill = this._getRegistrator().getQuill(); var wordListMatcher = (0, _wordLists2.default)(quill); var newLineMatcher = (0, _newLine2.default)(); var modulesConfig = (0, _extend.extend)({ toolbar: this._getModuleConfigByOption("toolbar"), variables: this._getModuleConfigByOption("variables"), dropImage: this._getBaseModuleConfig(), resizing: this._getModuleConfigByOption("mediaResizing"), mentions: this._getModuleConfigByOption("mentions"), clipboard: { matchVisual: false, matchers: [ ["p.MsoListParagraphCxSpFirst", wordListMatcher], ["p.MsoListParagraphCxSpMiddle", wordListMatcher], ["p.MsoListParagraphCxSpLast", wordListMatcher], [ELEMENT_NODE, (0, _textDecoration2.default)(quill)], [ELEMENT_NODE, newLineMatcher], [TEXT_NODE, newLineMatcher] ] } }, this._getCustomModules()); return modulesConfig }, _getModuleConfigByOption: function(userOptionName) { var optionValue = this.option(userOptionName); var config = {}; if (!(0, _type.isDefined)(optionValue)) { return } if (Array.isArray(optionValue)) { config[userOptionName] = optionValue } else { config = optionValue } return (0, _extend.extend)(this._getBaseModuleConfig(), config) }, _getBaseModuleConfig: function() { return { editorInstance: this } }, _getCustomModules: function() { var _this2 = this; var modules = {}; var moduleNames = this._getRegistrator().getRegisteredModuleNames(); moduleNames.forEach(function(modulePath) { modules[modulePath] = _this2._getBaseModuleConfig() }); return modules }, _textChangeHandler: function(newDelta, oldDelta, source) { var htmlMarkup = this._deltaConverter.toHtml(); var convertedValue = this._isMarkdownValue() ? this._updateValueByType(MARKDOWN_VALUE_TYPE, htmlMarkup) : htmlMarkup; var currentValue = this.option("value"); if (currentValue !== convertedValue && !this._isNullValueConverted(currentValue, convertedValue)) { this._isEditorUpdating = true; this.option("value", convertedValue) } this._finalizeContentRendering() }, _isNullValueConverted: function(currentValue, convertedValue) { return null === currentValue && "" === convertedValue }, _finalizeContentRendering: function() { if (this._contentRenderedDeferred) { this.clearHistory(); this._contentInitializedCallback.fire(); this._contentRenderedDeferred.resolve(); this._contentRenderedDeferred = void 0 } }, _updateValueByType: function(valueType, value) { var converter = this._markdownConverter; if (!(0, _type.isDefined)(converter)) { return } var currentValue = (0, _common.ensureDefined)(value, this.option("value")); return valueType === MARKDOWN_VALUE_TYPE ? converter.toMarkdown(currentValue) : converter.toHtml(currentValue) }, _isMarkdownValue: function() { return this.option("valueType") === MARKDOWN_VALUE_TYPE }, _resetEnabledState: function() { if (this._quillInstance) { var isEnabled = !(this.option("readOnly") || this.option("disabled")); this._quillInstance.enable(isEnabled) } }, _renderFormDialog: function() { var userOptions = (0, _extend.extend)(true, { width: "auto", height: "auto", closeOnOutsideClick: true }, this.option("formDialogOptions")); this._formDialog = new _formDialog2.default(this, userOptions) }, _getQuillContainer: function() { return this._$htmlContainer }, _optionChanged: function(args) { switch (args.name) { case "value": if (this._quillInstance) { if (this._isEditorUpdating) { this._isEditorUpdating = false } else { var updatedValue = this._isMarkdownValue() ? this._updateValueByType("HTML", args.value) : args.value; this._updateHtmlContent(updatedValue) } } else { this._$htmlContainer.html(args.value) } this._setSubmitValue(args.value); this.callBase(args); break; case "placeholder": case "variables": case "toolbar": case "mentions": case "customizeModules": this._invalidate(); break; case "valueType": this._prepareConverters(); var newValue = this._updateValueByType(args.value); if ("html" === args.value && this._quillInstance) { this._updateHtmlContent(newValue) } else { this.option("value", newValue) } break; case "readOnly": case "disabled": this.callBase(args); this._resetEnabledState(); break; case "formDialogOptions": this._renderFormDialog(); break; case "mediaResizing": if (!args.previousValue || !args.value) { this._invalidate() } else { this._quillInstance.getModule("resizing").option(args.name, args.value) } break; case "width": this.callBase(args); this._repaintToolbar(); break; default: this.callBase(args) } }, _repaintToolbar: function() { var toolbar = this._quillInstance.getModule("toolbar"); toolbar && toolbar.repaint() }, _updateHtmlContent: function(newMarkup) { var newDelta = this._quillInstance.clipboard.convert(newMarkup); this._quillInstance.setContents(newDelta) }, _clean: function() { if (this._quillInstance) { _events_engine2.default.off(this._getContent(), ".".concat(this.NAME)); this._quillInstance.off("text-change", this._textChangeHandlerWithContext); this._cleanCallback.fire() } this._abortUpdateContentTask(); this._cleanCallback.empty(); this._contentInitializedCallback.empty(); this.callBase() }, _abortUpdateContentTask: function() { if (this._updateContentTask) { this._updateContentTask.abort(); this._updateContentTask = void 0 } }, _applyQuillMethod: function(methodName, args) { if (this._quillInstance) { return this._quillInstance[methodName].apply(this._quillInstance, args) } }, _applyQuillHistoryMethod: function(methodName) { if (this._quillInstance && this._quillInstance.history) { this._quillInstance.history[methodName]() } }, addCleanCallback: function(callback) { this._cleanCallback.add(callback) }, addContentInitializedCallback: function(callback) { this._contentInitializedCallback.add(callback) }, register: function(components) { this._getRegistrator().registerModules(components); if (this._quillInstance) { this.repaint() } }, get: function(modulePath) { return this._getRegistrator().getQuill().import(modulePath) }, getQuillInstance: function() { return this._quillInstance }, getSelection: function() { return this._applyQuillMethod("getSelection") }, setSelection: function(index, length) { this._applyQuillMethod("setSelection", arguments) }, format: function(formatName, formatValue) { this._applyQuillMethod("format", arguments) }, formatText: function(index, length, formatName, formatValue) { this._applyQuillMethod("formatText", arguments) }, formatLine: function(index, length, formatName, formatValue) { this._applyQuillMethod("formatLine", arguments) }, getFormat: function(index, length) { return this._applyQuillMethod("getFormat", arguments) }, removeFormat: function(index, length) { return this._applyQuillMethod("removeFormat", arguments) }, clearHistory: function() { this._applyQuillHistoryMethod("clear") }, undo: function() { this._applyQuillHistoryMethod("undo") }, redo: function() { this._applyQuillHistoryMethod("redo") }, getLength: function() { return this._applyQuillMethod("getLength") }, "delete": function(index, length) { this._applyQuillMethod("deleteText", arguments) }, insertText: function(index, text, formats) { this._applyQuillMethod("insertText", arguments) }, insertEmbed: function(index, type, config) { this._applyQuillMethod("insertEmbed", arguments) }, showFormDialog: function(formConfig) { return this._formDialog.show(formConfig) }, formDialogOption: function(optionName, optionValue) { return this._formDialog.popupOption.apply(this._formDialog, arguments) }, focus: function() { this.callBase(); this._applyQuillMethod("focus") } }); (0, _component_registrator2.default)("dxHtmlEditor", HtmlEditor); module.exports = HtmlEditor;