UNPKG

@syncfusion/ej2-richtexteditor

Version:
342 lines (336 loc) 17.1 kB
import { removeClass, selectAll, isNullOrUndefined as isNOU, EventHandler, detach, createElement } from '@syncfusion/ej2-base'; import * as events from '../base/constant'; import { CLS_EXPAND_OPEN, CLS_TB_ITEM, CLS_ACTIVE, CLS_RTE_SOURCE_CODE_TXTAREA } from '../base/classes'; import * as CONSTANT from '../../common/constant'; import { RenderType } from '../base/enum'; import { KeyboardEvents } from '../actions/keyboard'; import { cleanHTMLString, resetContentEditableElements, cleanupInternalElements } from '../../common/util'; /** * Content module is used to render Rich Text Editor content * * @hidden */ var ViewSource = /** @class */ (function () { /** * Constructor for view source module * * @param {IRichTextEditor} parent - specifies the parent element. * @param {ServiceLocator} locator - specifies the locator. * @returns {void} */ function ViewSource(parent, locator) { this.parent = parent; var serviceLocator = locator; this.rendererFactory = serviceLocator.getService('rendererFactory'); this.addEventListener(); } ViewSource.prototype.addEventListener = function () { this.parent.on(events.sourceCode, this.sourceCode, this); this.parent.on(events.initialEnd, this.onInitialEnd, this); this.parent.on(events.updateSource, this.updateSourceCode, this); this.parent.on(events.destroy, this.destroy, this); }; ViewSource.prototype.onInitialEnd = function () { this.parent.formatter.editorManager.observer.on(CONSTANT.KEY_DOWN_HANDLER, this.onKeyDown, this); }; ViewSource.prototype.removeEventListener = function () { this.unWireEvent(); this.parent.off(events.sourceCode, this.sourceCode); this.parent.off(events.updateSource, this.updateSourceCode); this.parent.off(events.initialEnd, this.onInitialEnd); this.parent.off(events.destroy, this.destroy); this.parent.formatter.editorManager.observer.off(CONSTANT.KEY_DOWN_HANDLER, this.onKeyDown); }; ViewSource.prototype.getSourceCode = function () { return this.parent.createElement('textarea', { className: CLS_RTE_SOURCE_CODE_TXTAREA + this.parent.getCssClass(true) }); }; ViewSource.prototype.wireEvent = function (element) { this.keyboardModule = new KeyboardEvents(element, { keyAction: this.previewKeyDown.bind(this), keyConfigs: this.parent.formatter.keyConfig, eventName: 'keydown' }); EventHandler.add(this.previewElement, 'mousedown', this.mouseDownHandler, this); var getTextArea = this.parent.element.querySelector('.' + CLS_RTE_SOURCE_CODE_TXTAREA); if (this.parent.maxLength !== -1) { EventHandler.add(getTextArea, 'keydown', this.maxLengthHandlingCodeview, this); EventHandler.add(getTextArea, 'paste', this.onSourceCodePaste, this); } }; ViewSource.prototype.unWireEvent = function () { if (this.previewElement) { EventHandler.remove(this.previewElement, 'mousedown', this.mouseDownHandler); var getTextArea = this.parent.element.querySelector('.' + CLS_RTE_SOURCE_CODE_TXTAREA); EventHandler.remove(getTextArea, 'keydown', this.maxLengthHandlingCodeview); EventHandler.remove(getTextArea, 'paste', this.onSourceCodePaste); } if (this.keyboardModule && !this.keyboardModule.isDestroyed) { this.keyboardModule.destroy(); } }; ViewSource.prototype.wireBaseKeyDown = function () { this.parent.keyboardModule = new KeyboardEvents(this.contentModule.getEditPanel(), { keyAction: this.parent.keyDown.bind(this.parent), keyConfigs: this.parent.formatter.keyConfig, eventName: 'keydown' }); }; ViewSource.prototype.unWireBaseKeyDown = function () { this.parent.keyboardModule.destroy(); }; ViewSource.prototype.mouseDownHandler = function (e) { this.parent.notify(events.sourceCodeMouseDown, { args: e }); }; ViewSource.prototype.previewKeyDown = function (event) { switch (event.action) { case 'html-source': this.updateSourceCode(event); event.preventDefault(); break; case 'toolbar-focus': if (this.parent.toolbarSettings.enable && this.parent.getToolbarElement()) { var firstActiveItem = this.parent.getToolbarElement().querySelector('.e-toolbar-item:not(.e-overlay)[title]'); firstActiveItem.firstElementChild.removeAttribute('tabindex'); firstActiveItem.firstElementChild.focus(); } break; case 'escape': if (this.parent.element.classList.contains('e-rte-full-screen')) { this.parent.fullScreenModule.hideFullScreen(event); event.preventDefault(); } break; case 'full-screen': this.parent.fullScreenModule.showFullScreen(event); event.preventDefault(); break; } }; ViewSource.prototype.onKeyDown = function (e) { switch (e.event.action) { case 'html-source': e.event.preventDefault(); this.sourceCode(e); e.callBack({ requestType: 'SourceCode', editorMode: 'HTML', event: e.event }); break; } }; /** * sourceCode method * * @param {ClickEventArgs} args - specifies the click event. * @returns {void} * @hidden */ ViewSource.prototype.sourceCode = function (args) { var _this = this; this.parent.notify(events.hidePopup, {}); this.parent.isBlur = false; this.parent.trigger(events.actionBegin, { requestType: 'SourceCode', targetItem: 'SourceCode', args: args, cancel: false }, function (actionBeginArgs) { if (!actionBeginArgs.cancel) { var tbItems = selectAll('.' + CLS_TB_ITEM, _this.parent.element); _this.contentModule = _this.rendererFactory.getRenderer(RenderType.Content); var height = _this.parent.inputElement.getBoundingClientRect().height + _this.parent.toolbarModule.getExpandTBarPopHeight(); _this.parent.rootContainer.classList.add('e-source-code-enabled'); _this.parent.notify(events.updateToolbarItem, { targetItem: 'SourceCode', updateItem: 'Preview', baseToolbar: _this.parent.getBaseToolbarObject() }); if (isNOU(_this.previewElement)) { _this.previewElement = _this.getSourceCode(); } _this.parent.inputElement.innerHTML = cleanupInternalElements(_this.replaceAmpersand(_this.parent.inputElement.innerHTML), _this.parent.editorMode); _this.parent.updateValueData(); var rteContent = void 0; if (isNOU(_this.parent.element.querySelector('#' + _this.parent.getID() + '_source-view'))) { rteContent = _this.parent.createElement('div', { className: 'e-source-content', id: _this.parent.getID() + '_source-view', attrs: { style: 'height:' + height + 'px' } }); } else { rteContent = _this.parent.element.querySelector('#' + _this.parent.getID() + '_source-view'); rteContent.style.height = height + 'px'; } rteContent.appendChild(_this.previewElement); _this.parent.rootContainer.appendChild(rteContent); _this.getPanel().value = cleanupInternalElements(_this.getTextAreaValue(), _this.parent.editorMode); _this.parent.isBlur = false; _this.parent.disableToolbarItem(_this.parent.toolbarSettings.items); _this.parent.enableToolbarItem('SourceCode'); if (_this.parent.getToolbar()) { removeClass([_this.parent.getToolbar()], [CLS_EXPAND_OPEN]); } removeClass(tbItems, [CLS_ACTIVE]); var previewElement = _this.parent.element.querySelector('.e-source-content'); _this.wireEvent(previewElement); _this.unWireBaseKeyDown(); _this.previewElement.focus(); _this.parent.inputElement.innerHTML = cleanupInternalElements(_this.replaceAmpersand(_this.parent.inputElement.innerHTML), _this.parent.editorMode); _this.parent.updateValue(); _this.parent.trigger(events.actionComplete, { requestType: 'SourceCode', targetItem: 'SourceCode', args: args }); _this.parent.invokeChangeEvent(); if (!isNOU(_this.parent.saveInterval) && _this.parent.saveInterval > 0 && _this.parent.autoSaveOnIdle) { _this.codeViewTimeInterval = setInterval(function () { _this.parent.notify(events.updateValueOnIdle, {}); }, _this.parent.saveInterval); } } }); }; /** * updateSourceCode method * * @param {ClickEventArgs} args - specifies the click event. * @returns {void} * @hidden */ ViewSource.prototype.updateSourceCode = function (args) { var _this = this; this.parent.isBlur = false; this.parent.trigger(events.actionBegin, { requestType: 'Preview', targetItem: 'Preview', args: args, cancel: false }, function (actionBeginArgs) { if (!actionBeginArgs.cancel) { _this.parent.rootContainer.classList.remove('e-source-code-enabled'); var editHTML = _this.getPanel(); _this.parent.notify(events.updateToolbarItem, { targetItem: 'Preview', updateItem: 'SourceCode', baseToolbar: _this.parent.getBaseToolbarObject() }); if (!isNOU(editHTML)) { editHTML.value = _this.parent.enableHtmlSanitizer ? cleanHTMLString(_this.parent.htmlEditorModule.sanitizeHelper(editHTML.value), _this.parent.element) : cleanHTMLString(editHTML.value, _this.parent.element); editHTML.value = resetContentEditableElements(_this.replaceAmpersand(editHTML.value), _this.parent.editorMode); } var serializeValue = _this.parent.serializeValue(editHTML.value); var value = void 0; if (serializeValue === null || serializeValue === '') { if (_this.parent.enterKey === 'DIV') { value = '<div><br/></div>'; } else if (_this.parent.enterKey === 'BR') { value = '<br/>'; } else { value = '<p><br/></p>'; } } else { value = serializeValue; } var element = document.createElement('div'); element.innerHTML = value; var textString = element.textContent === '\n' ? '' : element.textContent; detach(element); element = null; if (_this.parent.maxLength >= 0 && textString.length > _this.parent.maxLength) { value = _this.contentModule.getEditPanel().innerHTML; } _this.contentModule.getEditPanel().innerHTML = resetContentEditableElements(_this.replaceAmpersand(value), _this.parent.editorMode); _this.parent.isBlur = false; _this.parent.enableToolbarItem(_this.parent.toolbarSettings.items); if (_this.parent.getToolbar()) { removeClass([_this.parent.getToolbar()], [CLS_EXPAND_OPEN]); } if (_this.parent.editorMode === 'HTML') { _this.parent.formatter.saveData(); } _this.unWireEvent(); _this.wireBaseKeyDown(); _this.parent.updateValue(); _this.contentModule.getEditPanel().focus(); _this.parent.trigger(events.actionComplete, { requestType: 'Preview', targetItem: 'Preview', args: args }); _this.parent.formatter.enableUndo(_this.parent); _this.parent.addAudioVideoWrapper(); clearTimeout(_this.codeViewTimeInterval); _this.parent.invokeChangeEvent(); _this.parent.notify(events.tableclass, {}); if (_this.parent.editorMode === 'HTML' && !isNOU(_this.parent.codeBlockModule)) { _this.parent.codeBlockModule.disableToolbarItems(); } } }); }; ViewSource.prototype.replaceAmpersand = function (value) { var _this = this; if (this.parent.editorMode === 'HTML') { var entities = ['times', 'divide', 'ne']; entities.forEach(function (entity) { // eslint-disable-next-line security/detect-non-literal-regexp var regex = new RegExp("&(amp;)*(" + entity + ")", 'g'); if (_this.parent.enableHtmlSanitizer) { var ampEntity = _this.parent.enableHtmlEncode ? "&amp;amp;amp;amp;" + entity : "&amp;amp;" + entity; value = value.replace(regex, ampEntity); } else { value = value.replace(regex, "&amp;" + entity); } }); } return value; }; ViewSource.prototype.maxLengthHandlingCodeview = function (e) { var getTextArea = this.parent.element.querySelector('.' + CLS_RTE_SOURCE_CODE_TXTAREA); var currentLength = this.getHtmlTextLengthRegex(getTextArea.value); var selectionLength = Math.abs(getTextArea.selectionStart - getTextArea.selectionEnd); var lengthAfterInput = currentLength - selectionLength + 1; var allowedKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Backspace', 'Delete', 'Shift', 'Home', 'End', 'Tab', 'Control', 'Meta', 'Alt', 'Escape']; // Allow all keyboard shortcuts (Ctrl/Cmd/Alt combinations) if (e.ctrlKey || e.metaKey || e.altKey) { return; } if ((this.parent.maxLength !== -1) && (lengthAfterInput > this.parent.maxLength) && ((allowedKeys.indexOf(e.key) === -1))) { e.preventDefault(); e.stopPropagation(); } }; ViewSource.prototype.getHtmlTextLengthRegex = function (html) { var tempElement = createElement('div'); tempElement.innerHTML = html; var textString = (tempElement).innerText; return textString.length; }; ViewSource.prototype.onSourceCodePaste = function (e) { var getTextArea = this.parent.element.querySelector('.' + CLS_RTE_SOURCE_CODE_TXTAREA); var pastedText = e.clipboardData.getData('text/plain') || ''; var selectionLength = Math.abs(getTextArea.selectionStart - getTextArea.selectionEnd); var pastedLength = this.getHtmlTextLengthRegex(pastedText); var currentContent = this.getHtmlTextLengthRegex(getTextArea.value); var finalLength = currentContent - selectionLength + pastedLength; if (finalLength > this.parent.maxLength) { e.preventDefault(); e.stopPropagation(); } }; ViewSource.prototype.getTextAreaValue = function () { return (this.contentModule.getEditPanel().innerHTML === '<p><br></p>') || (this.contentModule.getEditPanel().innerHTML === '<div><br></div>') || (this.contentModule.getEditPanel().innerHTML === '<br>') || (this.contentModule.getEditPanel().childNodes.length === 1 && (this.contentModule.getEditPanel().childNodes[0].tagName === 'P' && this.contentModule.getEditPanel().innerHTML.length === 7) || (this.contentModule.getEditPanel().childNodes[0].tagName === 'DIV' && this.contentModule.getEditPanel().innerHTML.length === 11)) ? '' : this.parent.value; }; /** * getPanel method * * @returns {HTMLTextAreaElement} - Specifies the Souce codetext area element. * @hidden */ ViewSource.prototype.getPanel = function () { return this.parent.element && this.parent.element.querySelector('.e-rte-srctextarea'); }; /** * Destroy the entire RichTextEditor. * * @returns {void} * @hidden */ ViewSource.prototype.destroy = function () { if (isNOU(this.parent)) { return; } this.removeEventListener(); }; return ViewSource; }()); export { ViewSource };