From 1853cfa78a460a4ad2580035a1840eb8f81db106 Mon Sep 17 00:00:00 2001 From: George Berezhnoy Date: Sun, 15 Jul 2018 16:04:59 +0300 Subject: [PATCH] Eslint --fix for project files (#280) --- build/codex-editor.js | 3765 +++++++++++++++++++- build/codex-editor.js.map | 2 +- example/plugins/code/code.js | 83 +- example/plugins/embed/embed.js | 326 +- example/plugins/header/header.js | 197 +- example/plugins/image/image.js | 866 +++-- example/plugins/instagram/instagram.js | 193 +- example/plugins/link/link.js | 441 +-- example/plugins/list/list.js | 312 +- example/plugins/quote/quote.js | 729 ++-- example/plugins/raw/raw.js | 58 +- example/plugins/text/text.js | 3 +- example/plugins/twitter/twitter.js | 376 +- src/components/core.js | 270 +- src/components/draw.js | 184 +- src/components/modules/_anchors.js | 118 +- src/components/modules/_callbacks.js | 1031 +++--- src/components/modules/_caret.js | 367 +- src/components/modules/_content.js | 174 +- src/components/modules/_destroyer.js | 110 +- src/components/modules/_notifications.js | 270 +- src/components/modules/_parser.js | 36 +- src/components/modules/_paste.js | 321 +- src/components/modules/_transport.js | 144 +- src/components/modules/toolbar/inline.js | 689 ++-- src/components/modules/toolbar/settings.js | 202 +- src/components/modules/toolbar/toolbar.js | 168 +- src/components/modules/toolbar/toolbox.js | 280 +- 28 files changed, 7234 insertions(+), 4481 deletions(-) diff --git a/build/codex-editor.js b/build/codex-editor.js index 8e56ae99..c3350f77 100644 --- a/build/codex-editor.js +++ b/build/codex-editor.js @@ -103,7 +103,7 @@ return /******/ (function(modules) { // webpackBootstrap /*! no static exports found */ /***/ (function(module, exports) { -module.exports = "\n\n\n \n\n\n\n \n\n\n\n \n\n\n\n \n\n\n\n \n \n \n \n \n\n\n\n \n\n\n\n \n\n\n\n \n\n\n\n \n\n" +module.exports = "\n\n\r\n \r\n\n\n\r\n \r\n\n\n\r\n \r\n\n\n\r\n \r\n\n\n\r\n \r\n \r\n \r\n \r\n \r\n\n\n\r\n \r\n\n\n\r\n \r\n\n\n\r\n \r\n\n\n\r\n \r\n\n" /***/ }), @@ -483,7 +483,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons */ // eslint-disable-next-line var modules = ["api-blocks.ts","api-events.ts","api-listener.ts","api-sanitizer.ts","api-saver.ts","api-selection.ts","api-toolbar.ts","api.ts","block-events.ts","blockManager.js","caret.js","events.js","listeners.js","renderer.js","sanitizer.js","saver.js","toolbar-blockSettings.js","toolbar-inline.ts","toolbar-toolbox.js","toolbar.js","tools.js","ui.js"].map(function (module) { - return __webpack_require__("./src/components/modules sync [^_](api-blocks.ts|api-events.ts|api-listener.ts|api-sanitizer.ts|api-saver.ts|api-selection.ts|api-toolbar.ts|api.ts|block-events.ts|blockManager.js|caret.js|events.js|listeners.js|renderer.js|sanitizer.js|saver.js|toolbar-blockSettings.js|toolbar-inline.ts|toolbar-toolbox.js|toolbar.js|tools.js|ui.js)$")("./" + module); + return __webpack_require__("./src/components/modules sync recursive ^\\.\\/.*$")("./" + module); }); /** @@ -2420,35 +2420,83 @@ module.exports = exports['default']; /***/ }), -/***/ "./src/components/modules sync [^_](api-blocks.ts|api-events.ts|api-listener.ts|api-sanitizer.ts|api-saver.ts|api-selection.ts|api-toolbar.ts|api.ts|block-events.ts|blockManager.js|caret.js|events.js|listeners.js|renderer.js|sanitizer.js|saver.js|toolbar-blockSettings.js|toolbar-inline.ts|toolbar-toolbox.js|toolbar.js|tools.js|ui.js)$": -/*!********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ - !*** ./src/components/modules sync nonrecursive [^_](api-blocks.ts|api-events.ts|api-listener.ts|api-sanitizer.ts|api-saver.ts|api-selection.ts|api-toolbar.ts|api.ts|block-events.ts|blockManager.js|caret.js|events.js|listeners.js|renderer.js|sanitizer.js|saver.js|toolbar-blockSettings.js|toolbar-inline.ts|toolbar-toolbox.js|toolbar.js|tools.js|ui.js)$ ***! - \********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/***/ "./src/components/modules sync recursive ^\\.\\/.*$": +/*!**********************************************!*\ + !*** ./src/components/modules sync ^\.\/.*$ ***! + \**********************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { var map = { + "./_anchors": "./src/components/modules/_anchors.js", + "./_anchors.js": "./src/components/modules/_anchors.js", + "./_callbacks": "./src/components/modules/_callbacks.js", + "./_callbacks.js": "./src/components/modules/_callbacks.js", + "./_caret": "./src/components/modules/_caret.js", + "./_caret.js": "./src/components/modules/_caret.js", + "./_content": "./src/components/modules/_content.js", + "./_content.js": "./src/components/modules/_content.js", + "./_destroyer": "./src/components/modules/_destroyer.js", + "./_destroyer.js": "./src/components/modules/_destroyer.js", + "./_notifications": "./src/components/modules/_notifications.js", + "./_notifications.js": "./src/components/modules/_notifications.js", + "./_parser": "./src/components/modules/_parser.js", + "./_parser.js": "./src/components/modules/_parser.js", + "./_paste": "./src/components/modules/_paste.js", + "./_paste.js": "./src/components/modules/_paste.js", + "./_transport": "./src/components/modules/_transport.js", + "./_transport.js": "./src/components/modules/_transport.js", + "./api": "./src/components/modules/api.ts", + "./api-blocks": "./src/components/modules/api-blocks.ts", "./api-blocks.ts": "./src/components/modules/api-blocks.ts", + "./api-events": "./src/components/modules/api-events.ts", "./api-events.ts": "./src/components/modules/api-events.ts", + "./api-listener": "./src/components/modules/api-listener.ts", "./api-listener.ts": "./src/components/modules/api-listener.ts", + "./api-sanitizer": "./src/components/modules/api-sanitizer.ts", "./api-sanitizer.ts": "./src/components/modules/api-sanitizer.ts", + "./api-saver": "./src/components/modules/api-saver.ts", "./api-saver.ts": "./src/components/modules/api-saver.ts", + "./api-selection": "./src/components/modules/api-selection.ts", "./api-selection.ts": "./src/components/modules/api-selection.ts", + "./api-toolbar": "./src/components/modules/api-toolbar.ts", "./api-toolbar.ts": "./src/components/modules/api-toolbar.ts", "./api.ts": "./src/components/modules/api.ts", + "./block-events": "./src/components/modules/block-events.ts", "./block-events.ts": "./src/components/modules/block-events.ts", + "./blockManager": "./src/components/modules/blockManager.js", "./blockManager.js": "./src/components/modules/blockManager.js", + "./caret": "./src/components/modules/caret.js", "./caret.js": "./src/components/modules/caret.js", + "./events": "./src/components/modules/events.js", "./events.js": "./src/components/modules/events.js", + "./listeners": "./src/components/modules/listeners.js", "./listeners.js": "./src/components/modules/listeners.js", + "./renderer": "./src/components/modules/renderer.js", "./renderer.js": "./src/components/modules/renderer.js", + "./sanitizer": "./src/components/modules/sanitizer.js", "./sanitizer.js": "./src/components/modules/sanitizer.js", + "./saver": "./src/components/modules/saver.js", "./saver.js": "./src/components/modules/saver.js", + "./toolbar": "./src/components/modules/toolbar.js", + "./toolbar-blockSettings": "./src/components/modules/toolbar-blockSettings.js", "./toolbar-blockSettings.js": "./src/components/modules/toolbar-blockSettings.js", + "./toolbar-inline": "./src/components/modules/toolbar-inline.ts", "./toolbar-inline.ts": "./src/components/modules/toolbar-inline.ts", + "./toolbar-toolbox": "./src/components/modules/toolbar-toolbox.js", "./toolbar-toolbox.js": "./src/components/modules/toolbar-toolbox.js", "./toolbar.js": "./src/components/modules/toolbar.js", + "./toolbar/inline": "./src/components/modules/toolbar/inline.js", + "./toolbar/inline.js": "./src/components/modules/toolbar/inline.js", + "./toolbar/settings": "./src/components/modules/toolbar/settings.js", + "./toolbar/settings.js": "./src/components/modules/toolbar/settings.js", + "./toolbar/toolbar": "./src/components/modules/toolbar/toolbar.js", + "./toolbar/toolbar.js": "./src/components/modules/toolbar/toolbar.js", + "./toolbar/toolbox": "./src/components/modules/toolbar/toolbox.js", + "./toolbar/toolbox.js": "./src/components/modules/toolbar/toolbox.js", + "./tools": "./src/components/modules/tools.js", "./tools.js": "./src/components/modules/tools.js", + "./ui": "./src/components/modules/ui.js", "./ui.js": "./src/components/modules/ui.js" }; @@ -2471,7 +2519,2765 @@ webpackContext.keys = function webpackContextKeys() { }; webpackContext.resolve = webpackContextResolve; module.exports = webpackContext; -webpackContext.id = "./src/components/modules sync [^_](api-blocks.ts|api-events.ts|api-listener.ts|api-sanitizer.ts|api-saver.ts|api-selection.ts|api-toolbar.ts|api.ts|block-events.ts|blockManager.js|caret.js|events.js|listeners.js|renderer.js|sanitizer.js|saver.js|toolbar-blockSettings.js|toolbar-inline.ts|toolbar-toolbox.js|toolbar.js|tools.js|ui.js)$"; +webpackContext.id = "./src/components/modules sync recursive ^\\.\\/.*$"; + +/***/ }), + +/***/ "./src/components/modules/_anchors.js": +/*!********************************************!*\ + !*** ./src/components/modules/_anchors.js ***! + \********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Codex Editor Anchors module + * + * @author Codex Team + * @version 1.0 + */ + +module.exports = function (anchors) { + var editor = codex.editor; + + anchors.input = null; + anchors.currentNode = null; + + anchors.settingsOpened = function (currentBlock) { + anchors.currentNode = currentBlock; + anchors.input.value = anchors.currentNode.dataset.anchor || ''; + }; + + anchors.anchorChanged = function (e) { + var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value); + + anchors.currentNode.dataset.anchor = newAnchor; + + if (newAnchor.trim() !== '') { + anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR); + } else { + anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR); + } + }; + + anchors.keyDownOnAnchorInput = function (e) { + if (e.keyCode == editor.core.keys.ENTER) { + e.preventDefault(); + e.stopPropagation(); + + e.target.blur(); + editor.toolbar.settings.close(); + } + }; + + anchors.keyUpOnAnchorInput = function (e) { + if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) { + e.stopPropagation(); + } + }; + + anchors.rusToTranslit = function (string) { + var ru = ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'], + en = ['A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya']; + + for (var i = 0; i < ru.length; i++) { + string = string.split(ru[i]).join(en[i]); + string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase()); + } + + string = string.replace(/[^0-9a-zA-Z_]+/g, '-'); + + return string; + }; + + return anchors; +}({}); + +/***/ }), + +/***/ "./src/components/modules/_callbacks.js": +/*!**********************************************!*\ + !*** ./src/components/modules/_callbacks.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * @module Codex Editor Callbacks module + * @description Module works with editor added Elements + * + * @author Codex Team + * @version 1.4.0 + */ + +module.exports = function (callbacks) { + var editor = codex.editor; + + /** + * used by UI module + * @description Routes all keydowns on document + * @param {Object} event + */ + callbacks.globalKeydown = function (event) { + switch (event.keyCode) { + case editor.core.keys.ENTER: + enterKeyPressed_(event);break; + } + }; + + /** + * used by UI module + * @description Routes all keydowns on redactors area + * @param {Object} event + */ + callbacks.redactorKeyDown = function (event) { + switch (event.keyCode) { + case editor.core.keys.TAB: + tabKeyPressedOnRedactorsZone_(event);break; + case editor.core.keys.ENTER: + enterKeyPressedOnRedactorsZone_(event);break; + case editor.core.keys.ESC: + escapeKeyPressedOnRedactorsZone_(event);break; + default: + defaultKeyPressedOnRedactorsZone_(event);break; + } + }; + + /** + * used by UI module + * @description Routes all keyup events + * @param {Object} event + */ + callbacks.globalKeyup = function (event) { + switch (event.keyCode) { + case editor.core.keys.UP: + case editor.core.keys.LEFT: + case editor.core.keys.RIGHT: + case editor.core.keys.DOWN: + arrowKeyPressed_(event);break; + } + }; + + /** + * @param {Object} event + * @private + * + * Handles behaviour when tab pressed + * @description if Content is empty show toolbox (if it is closed) or leaf tools + * uses Toolbars toolbox module to handle the situation + */ + var tabKeyPressedOnRedactorsZone_ = function tabKeyPressedOnRedactorsZone_(event) { + /** + * Wait for solution. Would like to know the behaviour + * @todo Add spaces + */ + event.preventDefault(); + + if (!editor.core.isBlockEmpty(editor.content.currentNode)) { + return; + } + + if (!editor.toolbar.opened) { + editor.toolbar.open(); + } + + if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) { + editor.toolbar.toolbox.open(); + } else { + editor.toolbar.toolbox.leaf(); + } + }; + + /** + * Handles global EnterKey Press + * @see enterPressedOnBlock_ + * @param {Object} event + */ + var enterKeyPressed_ = function enterKeyPressed_() { + if (editor.content.editorAreaHightlighted) { + /** + * it means that we lose input index, saved index before is not correct + * therefore we need to set caret when we insert new block + */ + editor.caret.inputIndex = -1; + + enterPressedOnBlock_(); + } + }; + + /** + * Callback for enter key pressing in first-level block area + * + * @param {Event} event + * @private + * + * @description Inserts new block with initial type from settings + */ + var enterPressedOnBlock_ = function enterPressedOnBlock_() { + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; + + editor.content.insertBlock({ + type: NEW_BLOCK_TYPE, + block: editor.tools[NEW_BLOCK_TYPE].render() + }, true); + + editor.toolbar.move(); + editor.toolbar.open(); + }; + + /** + * ENTER key handler + * + * @param {Object} event + * @private + * + * @description Makes new block with initial type from settings + */ + var enterKeyPressedOnRedactorsZone_ = function enterKeyPressedOnRedactorsZone_(event) { + if (event.target.contentEditable == 'true') { + /** Update input index */ + editor.caret.saveCurrentInputIndex(); + } + + var currentInputIndex = editor.caret.getCurrentInputIndex() || 0, + workingNode = editor.content.currentNode, + tool = workingNode.dataset.tool, + isEnterPressedOnToolbar = editor.toolbar.opened && editor.toolbar.current && event.target == editor.state.inputs[currentInputIndex]; + + /** The list of tools which needs the default browser behaviour */ + var enableLineBreaks = editor.tools[tool].enableLineBreaks; + + /** This type of block creates when enter is pressed */ + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; + + /** + * When toolbar is opened, select tool instead of making new paragraph + */ + if (isEnterPressedOnToolbar) { + event.preventDefault(); + + editor.toolbar.toolbox.toolClicked(event); + + editor.toolbar.close(); + + /** + * Stop other listeners callback executions + */ + event.stopPropagation(); + event.stopImmediatePropagation(); + + return; + } + + /** + * Allow paragraph lineBreaks with shift enter + * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation + */ + if (event.shiftKey || enableLineBreaks) { + event.stopPropagation(); + event.stopImmediatePropagation(); + return; + } + + var currentSelection = window.getSelection(), + currentSelectedNode = currentSelection.anchorNode, + caretAtTheEndOfText = editor.caret.position.atTheEnd(), + isTextNodeHasParentBetweenContenteditable = false; + + /** + * Allow making new

in same block by SHIFT+ENTER and forbids to prevent default browser behaviour + */ + if (event.shiftKey && !enableLineBreaks) { + editor.callback.enterPressedOnBlock(editor.content.currentBlock, event); + event.preventDefault(); + return; + } + + /** + * Workaround situation when caret at the Text node that has some wrapper Elements + * Split block cant handle this. + * We need to save default behavior + */ + isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true'; + + /** + * Split blocks when input has several nodes and caret placed in textNode + */ + if (currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT && !isTextNodeHasParentBetweenContenteditable && !caretAtTheEndOfText) { + event.preventDefault(); + + editor.core.log('Splitting Text node...'); + + editor.content.splitBlock(currentInputIndex); + + /** Show plus button when next input after split is empty*/ + if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) { + editor.toolbar.showPlusButton(); + } + } else { + var islastNode = editor.content.isLastNode(currentSelectedNode); + + if (islastNode && caretAtTheEndOfText) { + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + + editor.core.log('ENTER clicked in last textNode. Create new BLOCK'); + + editor.content.insertBlock({ + type: NEW_BLOCK_TYPE, + block: editor.tools[NEW_BLOCK_TYPE].render() + }, true); + + editor.toolbar.move(); + editor.toolbar.open(); + + /** Show plus button with empty block */ + editor.toolbar.showPlusButton(); + } + } + + /** get all inputs after new appending block */ + editor.ui.saveInputs(); + }; + + /** + * Escape behaviour + * @param event + * @private + * + * @description Closes toolbox and toolbar. Prevents default behaviour + */ + var escapeKeyPressedOnRedactorsZone_ = function escapeKeyPressedOnRedactorsZone_(event) { + /** Close all toolbar */ + editor.toolbar.close(); + + /** Close toolbox */ + editor.toolbar.toolbox.close(); + + event.preventDefault(); + }; + + /** + * @param {Event} event + * @private + * + * closes and moves toolbar + */ + var arrowKeyPressed_ = function arrowKeyPressed_(event) { + editor.content.workingNodeChanged(); + + /* Closing toolbar */ + editor.toolbar.close(); + editor.toolbar.move(); + }; + + /** + * @private + * @param {Event} event + * + * @description Closes all opened bars from toolbar. + * If block is mark, clears highlightning + */ + var defaultKeyPressedOnRedactorsZone_ = function defaultKeyPressedOnRedactorsZone_() { + editor.toolbar.close(); + + if (!editor.toolbar.inline.actionsOpened) { + editor.toolbar.inline.close(); + editor.content.clearMark(); + } + }; + + /** + * Handler when clicked on redactors area + * + * @protected + * @param event + * + * @description Detects clicked area. If it is first-level block area, marks as detected and + * on next enter press will be inserted new block + * Otherwise, save carets position (input index) and put caret to the editable zone. + * + * @see detectWhenClickedOnFirstLevelBlockArea_ + * + */ + callbacks.redactorClicked = function (event) { + detectWhenClickedOnFirstLevelBlockArea_(); + + editor.content.workingNodeChanged(event.target); + editor.ui.saveInputs(); + + var selectedText = editor.toolbar.inline.getSelectionText(), + firstLevelBlock; + + /** If selection range took off, then we hide inline toolbar */ + if (selectedText.length === 0) { + editor.toolbar.inline.close(); + } + + /** Update current input index in memory when caret focused into existed input */ + if (event.target.contentEditable == 'true') { + editor.caret.saveCurrentInputIndex(); + } + + if (editor.content.currentNode === null) { + /** + * If inputs in redactor does not exits, then we put input index 0 not -1 + */ + var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0; + + /** If we have any inputs */ + if (editor.state.inputs.length) { + /** getting firstlevel parent of input */ + firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]); + } + + /** If input is empty, then we set caret to the last input */ + if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) { + editor.caret.setToBlock(indexOfLastInput); + } else { + /** Create new input when caret clicked in redactors area */ + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; + + editor.content.insertBlock({ + type: NEW_BLOCK_TYPE, + block: editor.tools[NEW_BLOCK_TYPE].render() + }); + + /** If there is no inputs except inserted */ + if (editor.state.inputs.length === 1) { + editor.caret.setToBlock(indexOfLastInput); + } else { + /** Set caret to this appended input */ + editor.caret.setToNextBlock(indexOfLastInput); + } + } + } else { + /** Close all panels */ + editor.toolbar.settings.close(); + editor.toolbar.toolbox.close(); + } + + /** + * Move toolbar and open + */ + editor.toolbar.move(); + editor.toolbar.open(); + + var inputIsEmpty = !editor.content.currentNode.textContent.trim(), + currentNodeType = editor.content.currentNode.dataset.tool, + isInitialType = currentNodeType == editor.settings.initialBlockPlugin; + + /** Hide plus buttons */ + editor.toolbar.hidePlusButton(); + + if (!inputIsEmpty) { + /** Mark current block */ + editor.content.markBlock(); + } + + if (isInitialType && inputIsEmpty) { + /** Show plus button */ + editor.toolbar.showPlusButton(); + } + }; + + /** + * This method allows to define, is caret in contenteditable element or not. + * + * @private + * + * @description Otherwise, if we get TEXT node from range container, that will means we have input index. + * In this case we use default browsers behaviour (if plugin allows that) or overwritten action. + * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always + * specifies to the first-level block. Other cases we just ignore. + */ + var detectWhenClickedOnFirstLevelBlockArea_ = function detectWhenClickedOnFirstLevelBlockArea_() { + var selection = window.getSelection(), + anchorNode = selection.anchorNode, + flag = false; + + if (selection.rangeCount === 0) { + editor.content.editorAreaHightlighted = true; + } else { + if (!editor.core.isDomNode(anchorNode)) { + anchorNode = anchorNode.parentNode; + } + + /** Already founded, without loop */ + if (anchorNode.contentEditable == 'true') { + flag = true; + } + + while (anchorNode.contentEditable != 'true') { + anchorNode = anchorNode.parentNode; + + if (anchorNode.contentEditable == 'true') { + flag = true; + } + + if (anchorNode == document.body) { + break; + } + } + + /** If editable element founded, flag is "TRUE", Therefore we return "FALSE" */ + editor.content.editorAreaHightlighted = !flag; + } + }; + + /** + * Toolbar button click handler + * + * @param {Object} event - cursor to the button + * @protected + * + * @description gets current tool and calls render method + */ + callbacks.toolbarButtonClicked = function (event) { + var button = this; + + editor.toolbar.current = button.dataset.type; + + editor.toolbar.toolbox.toolClicked(event); + editor.toolbar.close(); + }; + + /** + * Show or Hide toolbox when plus button is clicked + */ + callbacks.plusButtonClicked = function () { + if (!editor.nodes.toolbox.classList.contains('opened')) { + editor.toolbar.toolbox.open(); + } else { + editor.toolbar.toolbox.close(); + } + }; + + /** + * Block handlers for KeyDown events + * + * @protected + * @param {Object} event + * + * Handles keydowns on block + * @see blockRightOrDownArrowPressed_ + * @see backspacePressed_ + * @see blockLeftOrUpArrowPressed_ + */ + callbacks.blockKeydown = function (event) { + var block = event.target; // event.target is input + + switch (event.keyCode) { + case editor.core.keys.DOWN: + case editor.core.keys.RIGHT: + blockRightOrDownArrowPressed_(event); + break; + + case editor.core.keys.BACKSPACE: + backspacePressed_(block, event); + break; + + case editor.core.keys.UP: + case editor.core.keys.LEFT: + blockLeftOrUpArrowPressed_(event); + break; + } + }; + + /** + * RIGHT or DOWN keydowns on block + * + * @param {Object} event + * @private + * + * @description watches the selection and gets closest editable element. + * Uses method getDeepestTextNodeFromPosition to get the last node of next block + * Sets caret if it is contenteditable + */ + var blockRightOrDownArrowPressed_ = function blockRightOrDownArrowPressed_(event) { + var selection = window.getSelection(), + inputs = editor.state.inputs, + focusedNode = selection.anchorNode, + focusedNodeHolder; + + /** Check for caret existance */ + if (!focusedNode) { + return false; + } + + /** Looking for closest (parent) contentEditable element of focused node */ + while (focusedNode.contentEditable != 'true') { + focusedNodeHolder = focusedNode.parentNode; + focusedNode = focusedNodeHolder; + } + + /** Input index in DOM level */ + var editableElementIndex = 0; + + while (focusedNode != inputs[editableElementIndex]) { + editableElementIndex++; + } + + /** + * Founded contentEditable element doesn't have childs + * Or maybe New created block + */ + if (!focusedNode.textContent) { + editor.caret.setToNextBlock(editableElementIndex); + return; + } + + /** + * Do nothing when caret doesn not reaches the end of last child + */ + var caretInLastChild = false, + caretAtTheEndOfText = false; + + var lastChild, deepestTextnode; + + lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1]; + + if (editor.core.isDomNode(lastChild)) { + deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length); + } else { + deepestTextnode = lastChild; + } + + caretInLastChild = selection.anchorNode == deepestTextnode; + caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset; + + if (!caretInLastChild || !caretAtTheEndOfText) { + editor.core.log('arrow [down|right] : caret does not reached the end'); + return false; + } + + editor.caret.setToNextBlock(editableElementIndex); + }; + + /** + * LEFT or UP keydowns on block + * + * @param {Object} event + * @private + * + * watches the selection and gets closest editable element. + * Uses method getDeepestTextNodeFromPosition to get the last node of previous block + * Sets caret if it is contenteditable + * + */ + var blockLeftOrUpArrowPressed_ = function blockLeftOrUpArrowPressed_(event) { + var selection = window.getSelection(), + inputs = editor.state.inputs, + focusedNode = selection.anchorNode, + focusedNodeHolder; + + /** Check for caret existance */ + if (!focusedNode) { + return false; + } + + /** + * LEFT or UP not at the beginning + */ + if (selection.anchorOffset !== 0) { + return false; + } + + /** Looking for parent contentEditable block */ + while (focusedNode.contentEditable != 'true') { + focusedNodeHolder = focusedNode.parentNode; + focusedNode = focusedNodeHolder; + } + + /** Input index in DOM level */ + var editableElementIndex = 0; + + while (focusedNode != inputs[editableElementIndex]) { + editableElementIndex++; + } + + /** + * Do nothing if caret is not at the beginning of first child + */ + var caretInFirstChild = false, + caretAtTheBeginning = false; + + var firstChild, deepestTextnode; + + /** + * Founded contentEditable element doesn't have childs + * Or maybe New created block + */ + if (!focusedNode.textContent) { + editor.caret.setToPreviousBlock(editableElementIndex); + return; + } + + firstChild = focusedNode.childNodes[0]; + + if (editor.core.isDomNode(firstChild)) { + deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0); + } else { + deepestTextnode = firstChild; + } + + caretInFirstChild = selection.anchorNode == deepestTextnode; + caretAtTheBeginning = selection.anchorOffset === 0; + + if (caretInFirstChild && caretAtTheBeginning) { + editor.caret.setToPreviousBlock(editableElementIndex); + } + }; + + /** + * Handles backspace keydown + * + * @param {Element} block + * @param {Object} event + * @private + * + * @description if block is empty, delete the block and set caret to the previous block + * If block is not empty, try to merge two blocks - current and previous + * But it we try'n to remove first block, then we should set caret to the next block, not previous. + * If we removed the last block, create new one + */ + var backspacePressed_ = function backspacePressed_(block, event) { + var currentInputIndex = editor.caret.getCurrentInputIndex(), + range, + selectionLength, + firstLevelBlocksCount; + + if (editor.core.isNativeInput(event.target)) { + /** If input value is empty - remove block */ + if (event.target.value.trim() == '') { + block.remove(); + } else { + return; + } + } + + if (block.textContent.trim()) { + range = editor.content.getRange(); + selectionLength = range.endOffset - range.startOffset; + + if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) { + editor.content.mergeBlocks(currentInputIndex); + } else { + return; + } + } + + if (!selectionLength) { + block.remove(); + } + + firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; + + /** + * If all blocks are removed + */ + if (firstLevelBlocksCount === 0) { + /** update currentNode variable */ + editor.content.currentNode = null; + + /** Inserting new empty initial block */ + editor.ui.addInitialBlock(); + + /** Updating inputs state after deleting last block */ + editor.ui.saveInputs(); + + /** Set to current appended block */ + window.setTimeout(function () { + editor.caret.setToPreviousBlock(1); + }, 10); + } else { + if (editor.caret.inputIndex !== 0) { + /** Target block is not first */ + editor.caret.setToPreviousBlock(editor.caret.inputIndex); + } else { + /** If we try to delete first block */ + editor.caret.setToNextBlock(editor.caret.inputIndex); + } + } + + editor.toolbar.move(); + + if (!editor.toolbar.opened) { + editor.toolbar.open(); + } + + /** Updating inputs state */ + editor.ui.saveInputs(); + + /** Prevent default browser behaviour */ + event.preventDefault(); + }; + + /** + * used by UI module + * Clicks on block settings button + * + * @param {Object} event + * @protected + * @description Opens toolbar settings + */ + callbacks.showSettingsButtonClicked = function (event) { + /** + * Get type of current block + * It uses to append settings from tool.settings property. + * ... + * Type is stored in data-type attribute on block + */ + var currentToolType = editor.content.currentNode.dataset.tool; + + editor.toolbar.settings.toggle(currentToolType); + + /** Close toolbox when settings button is active */ + editor.toolbar.toolbox.close(); + editor.toolbar.settings.hideRemoveActions(); + }; + + return callbacks; +}({}); + +/***/ }), + +/***/ "./src/components/modules/_caret.js": +/*!******************************************!*\ + !*** ./src/components/modules/_caret.js ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Codex Editor Caret Module + * + * @author Codex Team + * @version 1.0 + */ + +module.exports = function (caret) { + var editor = codex.editor; + + /** + * @var {int} InputIndex - editable element in DOM + */ + caret.inputIndex = null; + + /** + * @var {int} offset - caret position in a text node. + */ + caret.offset = null; + + /** + * @var {int} focusedNodeIndex - we get index of child node from first-level block + */ + caret.focusedNodeIndex = null; + + /** + * Creates Document Range and sets caret to the element. + * @protected + * @uses caret.save — if you need to save caret position + * @param {Element} el - Changed Node. + */ + caret.set = function (el, index, offset) { + offset = offset || caret.offset || 0; + index = index || caret.focusedNodeIndex || 0; + + var childs = el.childNodes, + nodeToSet; + + if (childs.length === 0) { + nodeToSet = el; + } else { + nodeToSet = childs[index]; + } + + /** If Element is INPUT */ + if (el.contentEditable != 'true') { + el.focus(); + return; + } + + if (editor.core.isDomNode(nodeToSet)) { + nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length); + } + + var range = document.createRange(), + selection = window.getSelection(); + + window.setTimeout(function () { + range.setStart(nodeToSet, offset); + range.setEnd(nodeToSet, offset); + + selection.removeAllRanges(); + selection.addRange(range); + + editor.caret.saveCurrentInputIndex(); + }, 20); + }; + + /** + * @protected + * Updates index of input and saves it in caret object + */ + caret.saveCurrentInputIndex = function () { + /** Index of Input that we paste sanitized content */ + var selection = window.getSelection(), + inputs = editor.state.inputs, + focusedNode = selection.anchorNode, + focusedNodeHolder; + + if (!focusedNode) { + return; + } + + /** Looking for parent contentEditable block */ + while (focusedNode.contentEditable != 'true') { + focusedNodeHolder = focusedNode.parentNode; + focusedNode = focusedNodeHolder; + } + + /** Input index in DOM level */ + var editableElementIndex = 0; + + while (focusedNode != inputs[editableElementIndex]) { + editableElementIndex++; + } + + caret.inputIndex = editableElementIndex; + }; + + /** + * Returns current input index (caret object) + */ + caret.getCurrentInputIndex = function () { + return caret.inputIndex; + }; + + /** + * @param {int} index - index of first-level block after that we set caret into next input + */ + caret.setToNextBlock = function (index) { + var inputs = editor.state.inputs, + nextInput = inputs[index + 1]; + + if (!nextInput) { + editor.core.log('We are reached the end'); + return; + } + + /** + * When new Block created or deleted content of input + * We should add some text node to set caret + */ + if (!nextInput.childNodes.length) { + var emptyTextElement = document.createTextNode(''); + + nextInput.appendChild(emptyTextElement); + } + + editor.caret.inputIndex = index + 1; + editor.caret.set(nextInput, 0, 0); + editor.content.workingNodeChanged(nextInput); + }; + + /** + * @param {int} index - index of target input. + * Sets caret to input with this index + */ + caret.setToBlock = function (index) { + var inputs = editor.state.inputs, + targetInput = inputs[index]; + + if (!targetInput) { + return; + } + + /** + * When new Block created or deleted content of input + * We should add some text node to set caret + */ + if (!targetInput.childNodes.length) { + var emptyTextElement = document.createTextNode(''); + + targetInput.appendChild(emptyTextElement); + } + + editor.caret.inputIndex = index; + editor.caret.set(targetInput, 0, 0); + editor.content.workingNodeChanged(targetInput); + }; + + /** + * @param {int} index - index of input + */ + caret.setToPreviousBlock = function (index) { + index = index || 0; + + var inputs = editor.state.inputs, + previousInput = inputs[index - 1], + lastChildNode, + lengthOfLastChildNode, + emptyTextElement; + + if (!previousInput) { + editor.core.log('We are reached first node'); + return; + } + + lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length); + lengthOfLastChildNode = lastChildNode.length; + + /** + * When new Block created or deleted content of input + * We should add some text node to set caret + */ + if (!previousInput.childNodes.length) { + emptyTextElement = document.createTextNode(''); + previousInput.appendChild(emptyTextElement); + } + editor.caret.inputIndex = index - 1; + editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode); + editor.content.workingNodeChanged(inputs[index - 1]); + }; + + caret.position = { + + atStart: function atStart() { + var selection = window.getSelection(), + anchorOffset = selection.anchorOffset, + anchorNode = selection.anchorNode, + firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode), + pluginsRender = firstLevelBlock.childNodes[0]; + + if (!editor.core.isDomNode(anchorNode)) { + anchorNode = anchorNode.parentNode; + } + + var isFirstNode = anchorNode === pluginsRender.childNodes[0], + isOffsetZero = anchorOffset === 0; + + return isFirstNode && isOffsetZero; + }, + + atTheEnd: function atTheEnd() { + var selection = window.getSelection(), + anchorOffset = selection.anchorOffset, + anchorNode = selection.anchorNode; + + /** Caret is at the end of input */ + return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length; + } + }; + + /** + * Inserts node at the caret location + * @param {HTMLElement|DocumentFragment} node + */ + caret.insertNode = function (node) { + var selection, + range, + lastNode = node; + + if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) { + lastNode = node.lastChild; + } + + selection = window.getSelection(); + + range = selection.getRangeAt(0); + range.deleteContents(); + + range.insertNode(node); + + range.setStartAfter(lastNode); + range.collapse(true); + + selection.removeAllRanges(); + selection.addRange(range); + }; + + return caret; +}({}); + +/***/ }), + +/***/ "./src/components/modules/_content.js": +/*!********************************************!*\ + !*** ./src/components/modules/_content.js ***! + \********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** + * Codex Editor Content Module + * Works with DOM + * + * @class Content + * @classdesc Class works provides COdex Editor appearance logic + * + * @author Codex Team + * @version 2.0.0 + */ + +var _dom = __webpack_require__(/*! ../dom */ "./src/components/dom.js"); + +var _dom2 = _interopRequireDefault(_dom); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +module.exports = function () { + _createClass(Content, null, [{ + key: 'name', + + /** + * Module key name + * @returns {string} + */ + get: function get() { + return 'Content'; + } + + /** + * @constructor + * + * @param {EditorConfig} config + */ + + }]); + + function Content(config) { + _classCallCheck(this, Content); + + this.config = config; + this.Editor = null; + + this.CSS = { + block: 'ce-block', + content: 'ce-block__content', + stretched: 'ce-block--stretched', + highlighted: 'ce-block--highlighted' + }; + + this._currentNode = null; + this._currentIndex = 0; + } + + /** + * Editor modules setter + * @param {object} Editor + */ + + + _createClass(Content, [{ + key: 'composeBlock_', + + + /** + * @private + * @param pluginHTML + * @param {Boolean} isStretched - make stretched block or not + * + * @description adds necessary information to wrap new created block by first-level holder + */ + value: function composeBlock_(pluginHTML) { + var isStretched = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + var block = _dom2.default.make('DIV', this.CSS.block), + blockContent = _dom2.default.make('DIV', this.CSS.content); + + blockContent.appendChild(pluginHTML); + block.appendChild(blockContent); + + if (isStretched) { + blockContent.classList.add(this.CSS.stretched); + } + + block.dataset.toolId = this._currentIndex++; + + return block; + } + }, { + key: 'getFirstLevelBlock', + + + /** + * Finds first-level block + * @description looks for first-level block. + * gets parent while node is not first-level + * + * @param {Element} node - selected or clicked in redactors area node + * @protected + * + */ + value: function getFirstLevelBlock(node) { + if (!_dom2.default.isElement(node)) { + node = node.parentNode; + } + + if (node === this.Editor.ui.nodes.redactor || node === document.body) { + return null; + } else { + while (node.classList && !node.classList.contains(this.CSS.block)) { + node = node.parentNode; + } + + return node; + } + } + }, { + key: 'insertBlock', + + + /** + * Insert new block to working area + * + * @param {HTMLElement} tool + * + * @returns {Number} tool index + * + */ + value: function insertBlock(tool) { + var newBlock = this.composeBlock_(tool); + + if (this.currentNode) { + this.currentNode.insertAdjacentElement('afterend', newBlock); + } else { + /** + * If redactor is empty, append as first child + */ + this.Editor.ui.nodes.redactor.appendChild(newBlock); + } + + /** + * Set new node as current + */ + this.currentNode = newBlock; + + return newBlock.dataset.toolId; + } + }, { + key: 'state', + set: function set(Editor) { + this.Editor = Editor; + } + + /** + * Get current working node + * + * @returns {null|HTMLElement} + */ + + }, { + key: 'currentNode', + get: function get() { + return this._currentNode; + } + + /** + * Set working node. Working node should be first level block, so we find it before set one to _currentNode property + * + * @param {HTMLElement} node + */ + , + set: function set(node) { + var firstLevelBlock = this.getFirstLevelBlock(node); + + this._currentNode = firstLevelBlock; + } + }]); + + return Content; +}(); + +// module.exports = (function (content) { +// +// let editor = codex.editor; +// +// /** +// * Links to current active block +// * @type {null | Element} +// */ +// content.currentNode = null; +// +// /** +// * clicked in redactor area +// * @type {null | Boolean} +// */ +// content.editorAreaHightlighted = null; +// +// /** +// * @deprecated +// * Synchronizes redactor with original textarea +// */ +// content.sync = function () { +// +// editor.core.log('syncing...'); +// +// /** +// * Save redactor content to editor.state +// */ +// editor.state.html = editor.nodes.redactor.innerHTML; +// +// }; +// +// /** +// * Appends background to the block +// * +// * @description add CSS class to highlight visually first-level block area +// */ +// content.markBlock = function () { +// +// editor.content.currentNode.classList.add(editor.ui.className.BLOCK_HIGHLIGHTED); +// +// }; +// +// /** +// * Clear background +// * +// * @description clears styles that highlights block +// */ +// content.clearMark = function () { +// +// if (editor.content.currentNode) { +// +// editor.content.currentNode.classList.remove(editor.ui.className.BLOCK_HIGHLIGHTED); +// +// } +// +// }; +// +// /** +// * Finds first-level block +// * +// * @param {Element} node - selected or clicked in redactors area node +// * @protected +// * +// * @description looks for first-level block. +// * gets parent while node is not first-level +// */ +// content.getFirstLevelBlock = function (node) { +// +// if (!editor.core.isDomNode(node)) { +// +// node = node.parentNode; +// +// } +// +// if (node === editor.nodes.redactor || node === document.body) { +// +// return null; +// +// } else { +// +// while(!node.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) { +// +// node = node.parentNode; +// +// } +// +// return node; +// +// } +// +// }; +// +// /** +// * Trigger this event when working node changed +// * @param {Element} targetNode - first-level of this node will be current +// * @protected +// * +// * @description If targetNode is first-level then we set it as current else we look for parents to find first-level +// */ +// content.workingNodeChanged = function (targetNode) { +// +// /** Clear background from previous marked block before we change */ +// editor.content.clearMark(); +// +// if (!targetNode) { +// +// return; +// +// } +// +// content.currentNode = content.getFirstLevelBlock(targetNode); +// +// }; +// +// /** +// * Replaces one redactor block with another +// * @protected +// * @param {Element} targetBlock - block to replace. Mostly currentNode. +// * @param {Element} newBlock +// * @param {string} newBlockType - type of new block; we need to store it to data-attribute +// * +// * [!] Function does not saves old block content. +// * You can get it manually and pass with newBlock.innerHTML +// */ +// content.replaceBlock = function (targetBlock, newBlock) { +// +// if (!targetBlock || !newBlock) { +// +// editor.core.log('replaceBlock: missed params'); +// return; +// +// } +// +// /** If target-block is not a frist-level block, then we iterate parents to find it */ +// while(!targetBlock.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) { +// +// targetBlock = targetBlock.parentNode; +// +// } +// +// /** Replacing */ +// editor.nodes.redactor.replaceChild(newBlock, targetBlock); +// +// /** +// * Set new node as current +// */ +// editor.content.workingNodeChanged(newBlock); +// +// /** +// * Add block handlers +// */ +// editor.ui.addBlockHandlers(newBlock); +// +// /** +// * Save changes +// */ +// editor.ui.saveInputs(); +// +// }; +// +// /** +// * @protected +// * +// * Inserts new block to redactor +// * Wrapps block into a DIV with BLOCK_CLASSNAME class +// * +// * @param blockData {object} +// * @param blockData.block {Element} element with block content +// * @param blockData.type {string} block plugin +// * @param needPlaceCaret {bool} pass true to set caret in new block +// * +// */ +// content.insertBlock = function ( blockData, needPlaceCaret ) { +// +// var workingBlock = editor.content.currentNode, +// newBlockContent = blockData.block, +// blockType = blockData.type, +// isStretched = blockData.stretched; +// +// var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched); +// +// if (workingBlock) { +// +// editor.core.insertAfter(workingBlock, newBlock); +// +// } else { +// +// /** +// * If redactor is empty, append as first child +// */ +// editor.nodes.redactor.appendChild(newBlock); +// +// } +// +// /** +// * Block handler +// */ +// editor.ui.addBlockHandlers(newBlock); +// +// /** +// * Set new node as current +// */ +// editor.content.workingNodeChanged(newBlock); +// +// /** +// * Save changes +// */ +// editor.ui.saveInputs(); +// +// +// if ( needPlaceCaret ) { +// +// /** +// * If we don't know input index then we set default value -1 +// */ +// var currentInputIndex = editor.caret.getCurrentInputIndex() || -1; +// +// +// if (currentInputIndex == -1) { +// +// +// var editableElement = newBlock.querySelector('[contenteditable]'), +// emptyText = document.createTextNode(''); +// +// editableElement.appendChild(emptyText); +// editor.caret.set(editableElement, 0, 0); +// +// editor.toolbar.move(); +// editor.toolbar.showPlusButton(); +// +// +// } else { +// +// if (currentInputIndex === editor.state.inputs.length - 1) +// return; +// +// /** Timeout for browsers execution */ +// window.setTimeout(function () { +// +// /** Setting to the new input */ +// editor.caret.setToNextBlock(currentInputIndex); +// editor.toolbar.move(); +// editor.toolbar.open(); +// +// }, 10); +// +// } +// +// } +// +// /** +// * Block is inserted, wait for new click that defined focusing on editors area +// * @type {boolean} +// */ +// content.editorAreaHightlighted = false; +// +// }; +// +// /** +// * Replaces blocks with saving content +// * @protected +// * @param {Element} noteToReplace +// * @param {Element} newNode +// * @param {Element} blockType +// */ +// content.switchBlock = function (blockToReplace, newBlock, tool) { +// +// tool = tool || editor.content.currentNode.dataset.tool; +// var newBlockComposed = composeNewBlock_(newBlock, tool); +// +// /** Replacing */ +// editor.content.replaceBlock(blockToReplace, newBlockComposed); +// +// /** Save new Inputs when block is changed */ +// editor.ui.saveInputs(); +// +// }; +// +// /** +// * Iterates between child noted and looking for #text node on deepest level +// * @protected +// * +// * @param {Element} block - node where find +// * @param {int} postiton - starting postion +// * Example: childNodex.length to find from the end +// * or 0 to find from the start +// * @return {Text} block +// * @uses DFS +// */ +// content.getDeepestTextNodeFromPosition = function (block, position) { +// +// /** +// * Clear Block from empty and useless spaces with trim. +// * Such nodes we should remove +// */ +// var blockChilds = block.childNodes, +// index, +// node, +// text; +// +// for(index = 0; index < blockChilds.length; index++) { +// +// node = blockChilds[index]; +// +// if (node.nodeType == editor.core.nodeTypes.TEXT) { +// +// text = node.textContent.trim(); +// +// /** Text is empty. We should remove this child from node before we start DFS +// * decrease the quantity of childs. +// */ +// if (text === '') { +// +// block.removeChild(node); +// position--; +// +// } +// +// } +// +// } +// +// if (block.childNodes.length === 0) { +// +// return document.createTextNode(''); +// +// } +// +// /** Setting default position when we deleted all empty nodes */ +// if ( position < 0 ) +// position = 1; +// +// var lookingFromStart = false; +// +// /** For looking from START */ +// if (position === 0) { +// +// lookingFromStart = true; +// position = 1; +// +// } +// +// while ( position ) { +// +// /** initial verticle of node. */ +// if ( lookingFromStart ) { +// +// block = block.childNodes[0]; +// +// } else { +// +// block = block.childNodes[position - 1]; +// +// } +// +// if ( block.nodeType == editor.core.nodeTypes.TAG ) { +// +// position = block.childNodes.length; +// +// } else if (block.nodeType == editor.core.nodeTypes.TEXT ) { +// +// position = 0; +// +// } +// +// } +// +// return block; +// +// }; +// +// /** +// * @private +// * @param {Element} block - current plugins render +// * @param {String} tool - plugins name +// * @param {Boolean} isStretched - make stretched block or not +// * +// * @description adds necessary information to wrap new created block by first-level holder +// */ +// var composeNewBlock_ = function (block, tool, isStretched) { +// +// var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}), +// blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {}); +// +// blockContent.appendChild(block); +// newBlock.appendChild(blockContent); +// +// if (isStretched) { +// +// blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED); +// +// } +// +// newBlock.dataset.tool = tool; +// return newBlock; +// +// }; +// +// /** +// * Returns Range object of current selection +// * @protected +// */ +// content.getRange = function () { +// +// var selection = window.getSelection().getRangeAt(0); +// +// return selection; +// +// }; +// +// /** +// * Divides block in two blocks (after and before caret) +// * +// * @protected +// * @param {int} inputIndex - target input index +// * +// * @description splits current input content to the separate blocks +// * When enter is pressed among the words, that text will be splited. +// */ +// content.splitBlock = function (inputIndex) { +// +// var selection = window.getSelection(), +// anchorNode = selection.anchorNode, +// anchorNodeText = anchorNode.textContent, +// caretOffset = selection.anchorOffset, +// textBeforeCaret, +// textNodeBeforeCaret, +// textAfterCaret, +// textNodeAfterCaret; +// +// var currentBlock = editor.content.currentNode.querySelector('[contentEditable]'); +// +// +// textBeforeCaret = anchorNodeText.substring(0, caretOffset); +// textAfterCaret = anchorNodeText.substring(caretOffset); +// +// textNodeBeforeCaret = document.createTextNode(textBeforeCaret); +// +// if (textAfterCaret) { +// +// textNodeAfterCaret = document.createTextNode(textAfterCaret); +// +// } +// +// var previousChilds = [], +// nextChilds = [], +// reachedCurrent = false; +// +// if (textNodeAfterCaret) { +// +// nextChilds.push(textNodeAfterCaret); +// +// } +// +// for ( var i = 0, child; !!(child = currentBlock.childNodes[i]); i++) { +// +// if ( child != anchorNode ) { +// +// if ( !reachedCurrent ) { +// +// previousChilds.push(child); +// +// } else { +// +// nextChilds.push(child); +// +// } +// +// } else { +// +// reachedCurrent = true; +// +// } +// +// } +// +// /** Clear current input */ +// editor.state.inputs[inputIndex].innerHTML = ''; +// +// /** +// * Append all childs founded before anchorNode +// */ +// var previousChildsLength = previousChilds.length; +// +// for(i = 0; i < previousChildsLength; i++) { +// +// editor.state.inputs[inputIndex].appendChild(previousChilds[i]); +// +// } +// +// editor.state.inputs[inputIndex].appendChild(textNodeBeforeCaret); +// +// /** +// * Append text node which is after caret +// */ +// var nextChildsLength = nextChilds.length, +// newNode = document.createElement('div'); +// +// for(i = 0; i < nextChildsLength; i++) { +// +// newNode.appendChild(nextChilds[i]); +// +// } +// +// newNode = newNode.innerHTML; +// +// /** This type of block creates when enter is pressed */ +// var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; +// +// /** +// * Make new paragraph with text after caret +// */ +// editor.content.insertBlock({ +// type : NEW_BLOCK_TYPE, +// block : editor.tools[NEW_BLOCK_TYPE].render({ +// text : newNode +// }) +// }, true ); +// +// }; +// +// /** +// * Merges two blocks — current and target +// * If target index is not exist, then previous will be as target +// * +// * @protected +// * @param {int} currentInputIndex +// * @param {int} targetInputIndex +// * +// * @description gets two inputs indexes and merges into one +// */ +// content.mergeBlocks = function (currentInputIndex, targetInputIndex) { +// +// /** If current input index is zero, then prevent method execution */ +// if (currentInputIndex === 0) { +// +// return; +// +// } +// +// var targetInput, +// currentInputContent = editor.state.inputs[currentInputIndex].innerHTML; +// +// if (!targetInputIndex) { +// +// targetInput = editor.state.inputs[currentInputIndex - 1]; +// +// } else { +// +// targetInput = editor.state.inputs[targetInputIndex]; +// +// } +// +// targetInput.innerHTML += currentInputContent; +// +// }; +// +// /** +// * Iterates all right siblings and parents, which has right siblings +// * while it does not reached the first-level block +// * +// * @param {Element} node +// * @return {boolean} +// */ +// content.isLastNode = function (node) { +// +// // console.log('погнали перебор родителей'); +// +// var allChecked = false; +// +// while ( !allChecked ) { +// +// // console.log('Смотрим на %o', node); +// // console.log('Проверим, пустые ли соседи справа'); +// +// if ( !allSiblingsEmpty_(node) ) { +// +// // console.log('Есть непустые соседи. Узел не последний. Выходим.'); +// return false; +// +// } +// +// node = node.parentNode; +// +// /** +// * Проверяем родителей до тех пор, пока не найдем блок первого уровня +// */ +// if ( node.classList.contains(editor.ui.className.BLOCK_CONTENT) ) { +// +// allChecked = true; +// +// } +// +// } +// +// return true; +// +// }; +// +// /** +// * Checks if all element right siblings is empty +// * @param node +// */ +// var allSiblingsEmpty_ = function (node) { +// +// /** +// * Нужно убедиться, что после пустого соседа ничего нет +// */ +// var sibling = node.nextSibling; +// +// while ( sibling ) { +// +// if (sibling.textContent.length) { +// +// return false; +// +// } +// +// sibling = sibling.nextSibling; +// +// } +// +// return true; +// +// }; +// +// /** +// * @public +// * +// * @param {string} htmlData - html content as string +// * @param {string} plainData - plain text +// * @return {string} - html content as string +// */ +// content.wrapTextWithParagraphs = function (htmlData, plainData) { +// +// if (!htmlData.trim()) { +// +// return wrapPlainTextWithParagraphs(plainData); +// +// } +// +// var wrapper = document.createElement('DIV'), +// newWrapper = document.createElement('DIV'), +// i, +// paragraph, +// firstLevelBlocks = ['DIV', 'P'], +// blockTyped, +// node; +// +// /** +// * Make HTML Element to Wrap Text +// * It allows us to work with input data as HTML content +// */ +// wrapper.innerHTML = htmlData; +// paragraph = document.createElement('P'); +// +// for (i = 0; i < wrapper.childNodes.length; i++) { +// +// node = wrapper.childNodes[i]; +// +// blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1; +// +// /** +// * If node is first-levet +// * we add this node to our new wrapper +// */ +// if ( blockTyped ) { +// +// /** +// * If we had splitted inline nodes to paragraph before +// */ +// if ( paragraph.childNodes.length ) { +// +// newWrapper.appendChild(paragraph.cloneNode(true)); +// +// /** empty paragraph */ +// paragraph = null; +// paragraph = document.createElement('P'); +// +// } +// +// newWrapper.appendChild(node.cloneNode(true)); +// +// } else { +// +// /** Collect all inline nodes to one as paragraph */ +// paragraph.appendChild(node.cloneNode(true)); +// +// /** if node is last we should append this node to paragraph and paragraph to new wrapper */ +// if ( i == wrapper.childNodes.length - 1 ) { +// +// newWrapper.appendChild(paragraph.cloneNode(true)); +// +// } +// +// } +// +// } +// +// return newWrapper.innerHTML; +// +// }; +// +// /** +// * Splits strings on new line and wraps paragraphs with

tag +// * @param plainText +// * @returns {string} +// */ +// var wrapPlainTextWithParagraphs = function (plainText) { +// +// if (!plainText) return ''; +// +// return '

' + plainText.split('\n\n').join('

') + '

'; +// +// }; +// +// /** +// * Finds closest Contenteditable parent from Element +// * @param {Element} node element looking from +// * @return {Element} node contenteditable +// */ +// content.getEditableParent = function (node) { +// +// while (node && node.contentEditable != 'true') { +// +// node = node.parentNode; +// +// } +// +// return node; +// +// }; +// +// /** +// * Clear editors content +// * +// * @param {Boolean} all — if true, delete all article data (content, id, etc.) +// */ +// content.clear = function (all) { +// +// editor.nodes.redactor.innerHTML = ''; +// editor.content.sync(); +// editor.ui.saveInputs(); +// if (all) { +// +// editor.state.blocks = {}; +// +// } else if (editor.state.blocks) { +// +// editor.state.blocks.items = []; +// +// } +// +// editor.content.currentNode = null; +// +// }; +// +// /** +// * +// * Load new data to editor +// * If editor is not empty, just append articleData.items +// * +// * @param articleData.items +// */ +// content.load = function (articleData) { +// +// var currentContent = Object.assign({}, editor.state.blocks); +// +// editor.content.clear(); +// +// if (!Object.keys(currentContent).length) { +// +// editor.state.blocks = articleData; +// +// } else if (!currentContent.items) { +// +// currentContent.items = articleData.items; +// editor.state.blocks = currentContent; +// +// } else { +// +// currentContent.items = currentContent.items.concat(articleData.items); +// editor.state.blocks = currentContent; +// +// } +// +// editor.renderer.makeBlocksFromData(); +// +// }; +// +// return content; +// +// })({}); + +/***/ }), + +/***/ "./src/components/modules/_destroyer.js": +/*!**********************************************!*\ + !*** ./src/components/modules/_destroyer.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +/** + * Codex Editor Destroyer module + * + * @auhor Codex Team + * @version 1.0 + */ + +module.exports = function (destroyer) { + var editor = codex.editor; + + destroyer.removeNodes = function () { + editor.nodes.wrapper.remove(); + editor.nodes.notifications.remove(); + }; + + destroyer.destroyPlugins = function () { + for (var tool in editor.tools) { + if (typeof editor.tools[tool].destroy === 'function') { + editor.tools[tool].destroy(); + } + } + }; + + destroyer.destroyScripts = function () { + var scripts = document.getElementsByTagName('SCRIPT'); + + for (var i = 0; i < scripts.length; i++) { + if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) { + scripts[i].remove(); + i--; + } + } + }; + + /** + * Delete editor data from webpage. + * You should send settings argument with boolean flags: + * @param settings.ui- remove redactor event listeners and DOM nodes + * @param settings.scripts - remove redactor scripts from DOM + * @param settings.plugins - remove plugin's objects + * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true + * } + * + */ + destroyer.destroy = function (settings) { + if (!settings || (typeof settings === 'undefined' ? 'undefined' : _typeof(settings)) !== 'object') { + return; + } + + if (settings.ui) { + destroyer.removeNodes(); + editor.listeners.removeAll(); + } + + if (settings.scripts) { + destroyer.destroyScripts(); + } + + if (settings.plugins) { + destroyer.destroyPlugins(); + } + + if (settings.ui && settings.scripts && settings.core) { + delete codex.editor; + } + }; + + return destroyer; +}({}); + +/***/ }), + +/***/ "./src/components/modules/_notifications.js": +/*!**************************************************!*\ + !*** ./src/components/modules/_notifications.js ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Codex Editor Notification Module + * + * @author Codex Team + * @version 1.0 + */ + +module.exports = function (notifications) { + var editor = codex.editor; + + var queue = []; + + var addToQueue = function addToQueue(settings) { + queue.push(settings); + + var index = 0; + + while (index < queue.length && queue.length > 5) { + if (queue[index].type == 'confirm' || queue[index].type == 'prompt') { + index++; + continue; + } + + queue[index].close(); + queue.splice(index, 1); + } + }; + + notifications.createHolder = function () { + var holder = editor.draw.node('DIV', 'cdx-notifications-block'); + + editor.nodes.notifications = document.body.appendChild(holder); + + return holder; + }; + + /** + * Error notificator. Shows block with message + * @protected + */ + notifications.errorThrown = function (errorMsg, event) { + editor.notifications.notification({ message: 'This action is not available currently', type: event.type }); + }; + + /** + * + * Appends notification + * + * settings = { + * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type + * message - notification message + * okMsg - confirm button text (default - 'Ok') + * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types + * confirm - function-handler for ok button click + * cancel - function-handler for cancel button click. Only for confirm and prompt types + * time - time (in seconds) after which notification will close (default - 10s) + * } + * + * @param settings + */ + notifications.notification = function (constructorSettings) { + /** Private vars and methods */ + var notification = null, + cancel = null, + type = null, + confirm = null, + inputField = null; + + var confirmHandler = function confirmHandler() { + close(); + + if (typeof confirm !== 'function') { + return; + } + + if (type == 'prompt') { + confirm(inputField.value); + return; + } + + confirm(); + }; + + var cancelHandler = function cancelHandler() { + close(); + + if (typeof cancel !== 'function') { + return; + } + + cancel(); + }; + + /** Public methods */ + function create(settings) { + if (!(settings && settings.message)) { + editor.core.log('Can\'t create notification. Message is missed'); + return; + } + + settings.type = settings.type || 'alert'; + settings.time = settings.time * 1000 || 10000; + + var wrapper = editor.draw.node('DIV', 'cdx-notification'), + message = editor.draw.node('DIV', 'cdx-notification__message'), + input = editor.draw.node('INPUT', 'cdx-notification__input'), + okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'), + cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn'); + + message.textContent = settings.message; + okBtn.textContent = settings.okMsg || 'ОК'; + cancelBtn.textContent = settings.cancelMsg || 'Отмена'; + + editor.listeners.add(okBtn, 'click', confirmHandler); + editor.listeners.add(cancelBtn, 'click', cancelHandler); + + wrapper.appendChild(message); + + if (settings.type == 'prompt') { + wrapper.appendChild(input); + } + + wrapper.appendChild(okBtn); + + if (settings.type == 'prompt' || settings.type == 'confirm') { + wrapper.appendChild(cancelBtn); + } + + wrapper.classList.add('cdx-notification-' + settings.type); + wrapper.dataset.type = settings.type; + + notification = wrapper; + type = settings.type; + confirm = settings.confirm; + cancel = settings.cancel; + inputField = input; + + if (settings.type != 'prompt' && settings.type != 'confirm') { + window.setTimeout(close, settings.time); + } + }; + + /** + * Show notification block + */ + function send() { + editor.nodes.notifications.appendChild(notification); + inputField.focus(); + + editor.nodes.notifications.classList.add('cdx-notification__notification-appending'); + + window.setTimeout(function () { + editor.nodes.notifications.classList.remove('cdx-notification__notification-appending'); + }, 100); + + addToQueue({ type: type, close: close }); + }; + + /** + * Remove notification block + */ + function close() { + notification.remove(); + }; + + if (constructorSettings) { + create(constructorSettings); + send(); + } + + return { + create: create, + send: send, + close: close + }; + }; + + notifications.clear = function () { + editor.nodes.notifications.innerHTML = ''; + queue = []; + }; + + return notifications; +}({}); + +/***/ }), + +/***/ "./src/components/modules/_parser.js": +/*!*******************************************!*\ + !*** ./src/components/modules/_parser.js ***! + \*******************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Codex Editor Parser Module + * + * @author Codex Team + * @version 1.1 + */ + +module.exports = function (parser) { + var editor = codex.editor; + + /** inserting text */ + parser.insertPastedContent = function (blockType, tag) { + editor.content.insertBlock({ + type: blockType.type, + block: blockType.render({ + text: tag.innerHTML + }) + }); + }; + + /** + * Check DOM node for display style: separated block or child-view + */ + parser.isFirstLevelBlock = function (node) { + return node.nodeType == editor.core.nodeTypes.TAG && node.classList.contains(editor.ui.className.BLOCK_CLASSNAME); + }; + + return parser; +}({}); + +/***/ }), + +/***/ "./src/components/modules/_paste.js": +/*!******************************************!*\ + !*** ./src/components/modules/_paste.js ***! + \******************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Codex Editor Paste module + * + * @author Codex Team + * @version 1.1.1 + */ + +module.exports = function (paste) { + var editor = codex.editor; + + var patterns = []; + + paste.prepare = function () { + var tools = editor.tools; + + for (var tool in tools) { + if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) { + continue; + } + + tools[tool].renderOnPastePatterns.map(function (pattern) { + patterns.push(pattern); + }); + } + + return Promise.resolve(); + }; + + /** + * Saves data + * @param event + */ + paste.pasted = function (event) { + var clipBoardData = event.clipboardData || window.clipboardData, + content = clipBoardData.getData('Text'); + + var result = analize(content); + + if (result) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + + return result; + }; + + /** + * Analizes pated string and calls necessary method + */ + + var analize = function analize(string) { + var result = false, + content = editor.content.currentNode, + plugin = content.dataset.tool; + + patterns.map(function (pattern) { + var execArray = pattern.regex.exec(string), + match = execArray && execArray[0]; + + if (match && match === string.trim()) { + /** current block is not empty */ + if (content.textContent.trim() && plugin == editor.settings.initialBlockPlugin) { + pasteToNewBlock_(); + } + + pattern.callback(string, pattern); + result = true; + } + }); + + return result; + }; + + var pasteToNewBlock_ = function pasteToNewBlock_() { + /** Create new initial block */ + editor.content.insertBlock({ + + type: editor.settings.initialBlockPlugin, + block: editor.tools[editor.settings.initialBlockPlugin].render({ + text: '' + }) + + }, false); + }; + + /** + * This method prevents default behaviour. + * + * @param {Object} event + * @protected + * + * @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes. + * Firstly, we need to memorize the caret position. We can do that by getting the range of selection. + * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node + */ + paste.blockPasteCallback = function (event) { + if (!needsToHandlePasteEvent(event.target)) { + return; + } + + /** Prevent default behaviour */ + event.preventDefault(); + + /** get html pasted data - dirty data */ + var htmlData = event.clipboardData.getData('text/html'), + plainData = event.clipboardData.getData('text/plain'); + + /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/ + var paragraphs = editor.draw.node('DIV', '', {}), + cleanData, + wrappedData; + + /** Create fragment, that we paste to range after proccesing */ + cleanData = editor.sanitizer.clean(htmlData); + + /** + * We wrap pasted text with

tags to split it logically + * @type {string} + */ + wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData); + paragraphs.innerHTML = wrappedData; + + /** + * If there only one paragraph, just insert in at the caret location + */ + if (paragraphs.childNodes.length == 1) { + emulateUserAgentBehaviour(paragraphs.firstChild); + return; + } + + insertPastedParagraphs(paragraphs.childNodes); + }; + + /** + * Checks if we should handle paste event on block + * @param block + * + * @return {boolean} + */ + var needsToHandlePasteEvent = function needsToHandlePasteEvent(block) { + /** If area is input or textarea then allow default behaviour */ + if (editor.core.isNativeInput(block)) { + return false; + } + + var editableParent = editor.content.getEditableParent(block); + + /** Allow paste when event target placed in Editable element */ + if (!editableParent) { + return false; + } + + return true; + }; + + /** + * Inserts new initial plugin blocks with data in paragraphs + * + * @param {Array} paragraphs - array of paragraphs (

) whit content, that should be inserted + */ + var insertPastedParagraphs = function insertPastedParagraphs(paragraphs) { + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin, + currentNode = editor.content.currentNode; + + paragraphs.forEach(function (paragraph) { + /** Don't allow empty paragraphs */ + if (editor.core.isBlockEmpty(paragraph)) { + return; + } + + editor.content.insertBlock({ + type: NEW_BLOCK_TYPE, + block: editor.tools[NEW_BLOCK_TYPE].render({ + text: paragraph.innerHTML + }) + }); + + editor.caret.inputIndex++; + }); + + editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1); + + /** + * If there was no data in working node, remove it + */ + if (editor.core.isBlockEmpty(currentNode)) { + currentNode.remove(); + editor.ui.saveInputs(); + } + }; + + /** + * Inserts node content at the caret position + * + * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location + */ + var emulateUserAgentBehaviour = function emulateUserAgentBehaviour(node) { + var newNode; + + if (node.childElementCount) { + newNode = document.createDocumentFragment(); + + node.childNodes.forEach(function (current) { + if (!editor.core.isDomNode(current) && current.data.trim() === '') { + return; + } + + newNode.appendChild(current.cloneNode(true)); + }); + } else { + newNode = document.createTextNode(node.textContent); + } + + editor.caret.insertNode(newNode); + }; + + return paste; +}({}); + +/***/ }), + +/***/ "./src/components/modules/_transport.js": +/*!**********************************************!*\ + !*** ./src/components/modules/_transport.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * + * Codex.Editor Transport Module + * + * @copyright 2017 Codex-Team + * @version 1.2.0 + */ + +module.exports = function (transport) { + var editor = codex.editor; + + /** + * @private {Object} current XmlHttpRequest instance + */ + var currentRequest = null; + + /** + * @type {null} | {DOMElement} input - keeps input element in memory + */ + transport.input = null; + + /** + * @property {Object} arguments - keep plugin settings and defined callbacks + */ + transport.arguments = null; + + /** + * Prepares input element where will be files + */ + transport.prepare = function () { + var input = editor.draw.node('INPUT', '', { type: 'file' }); + + editor.listeners.add(input, 'change', editor.transport.fileSelected); + editor.transport.input = input; + }; + + /** Clear input when files is uploaded */ + transport.clearInput = function () { + /** Remove old input */ + transport.input = null; + + /** Prepare new one */ + transport.prepare(); + }; + + /** + * Callback for file selection + * @param {Event} event + */ + transport.fileSelected = function () { + var input = this, + i, + files = input.files, + formData = new FormData(); + + if (editor.transport.arguments.multiple === true) { + for (i = 0; i < files.length; i++) { + formData.append('files[]', files[i], files[i].name); + } + } else { + formData.append('files', files[0], files[0].name); + } + + currentRequest = editor.core.ajax({ + type: 'POST', + data: formData, + url: editor.transport.arguments.url, + beforeSend: editor.transport.arguments.beforeSend, + success: editor.transport.arguments.success, + error: editor.transport.arguments.error, + progress: editor.transport.arguments.progress + }); + + /** Clear input */ + transport.clearInput(); + }; + + /** + * Use plugin callbacks + * @protected + * + * @param {Object} args - can have : + * @param {String} args.url - fetch URL + * @param {Function} args.beforeSend - function calls before sending ajax + * @param {Function} args.success - success callback + * @param {Function} args.error - on error handler + * @param {Function} args.progress - xhr onprogress handler + * @param {Boolean} args.multiple - allow select several files + * @param {String} args.accept - adds accept attribute + */ + transport.selectAndUpload = function (args) { + transport.arguments = args; + + if (args.multiple === true) { + transport.input.setAttribute('multiple', 'multiple'); + } + + if (args.accept) { + transport.input.setAttribute('accept', args.accept); + } + + transport.input.click(); + }; + + transport.abort = function () { + currentRequest.abort(); + + currentRequest = null; + }; + + return transport; +}({}); /***/ }), @@ -6671,6 +9477,947 @@ module.exports = exports['default']; /***/ }), +/***/ "./src/components/modules/toolbar/inline.js": +/*!**************************************************!*\ + !*** ./src/components/modules/toolbar/inline.js ***! + \**************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Inline toolbar + * + * Contains from tools: + * Bold, Italic, Underline and Anchor + * + * @author Codex Team + * @version 1.0 + */ + +module.exports = function (inline) { + var editor = codex.editor; + + inline.buttonsOpened = null; + inline.actionsOpened = null; + inline.wrappersOffset = null; + + /** + * saving selection that need for execCommand for styling + * + */ + inline.storedSelection = null; + + /** + * @protected + * + * Open inline toobar + */ + inline.show = function () { + var currentNode = editor.content.currentNode, + tool = currentNode.dataset.tool, + plugin; + + /** + * tool allowed to open inline toolbar + */ + plugin = editor.tools[tool]; + + if (!plugin.showInlineToolbar) return; + + var selectedText = inline.getSelectionText(), + toolbar = editor.nodes.inlineToolbar.wrapper; + + if (selectedText.length > 0) { + /** Move toolbar and open */ + editor.toolbar.inline.move(); + + /** Open inline toolbar */ + toolbar.classList.add('opened'); + + /** show buttons of inline toolbar */ + editor.toolbar.inline.showButtons(); + } + }; + + /** + * @protected + * + * Closes inline toolbar + */ + inline.close = function () { + var toolbar = editor.nodes.inlineToolbar.wrapper; + + toolbar.classList.remove('opened'); + }; + + /** + * @private + * + * Moving toolbar + */ + inline.move = function () { + if (!this.wrappersOffset) { + this.wrappersOffset = this.getWrappersOffset(); + } + + var coords = this.getSelectionCoords(), + defaultOffset = 0, + toolbar = editor.nodes.inlineToolbar.wrapper, + newCoordinateX, + newCoordinateY; + + if (toolbar.offsetHeight === 0) { + defaultOffset = 40; + } + + newCoordinateX = coords.x - this.wrappersOffset.left; + newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight; + + toolbar.style.transform = 'translate3D(' + Math.floor(newCoordinateX) + 'px, ' + Math.floor(newCoordinateY) + 'px, 0)'; + + /** Close everything */ + editor.toolbar.inline.closeButtons(); + editor.toolbar.inline.closeAction(); + }; + + /** + * @private + * + * Tool Clicked + */ + + inline.toolClicked = function (event, type) { + /** + * For simple tools we use default browser function + * For more complicated tools, we should write our own behavior + */ + switch (type) { + case 'createLink': + editor.toolbar.inline.createLinkAction(event, type);break; + default: + editor.toolbar.inline.defaultToolAction(type);break; + } + + /** + * highlight buttons + * after making some action + */ + editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); + }; + + /** + * @private + * + * Saving wrappers offset in DOM + */ + inline.getWrappersOffset = function () { + var wrapper = editor.nodes.wrapper, + offset = this.getOffset(wrapper); + + this.wrappersOffset = offset; + return offset; + }; + + /** + * @private + * + * Calculates offset of DOM element + * + * @param el + * @returns {{top: number, left: number}} + */ + inline.getOffset = function (el) { + var _x = 0; + var _y = 0; + + while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) { + _x += el.offsetLeft + el.clientLeft; + _y += el.offsetTop + el.clientTop; + el = el.offsetParent; + } + return { top: _y, left: _x }; + }; + + /** + * @private + * + * Calculates position of selected text + * @returns {{x: number, y: number}} + */ + inline.getSelectionCoords = function () { + var sel = document.selection, + range; + var x = 0, + y = 0; + + if (sel) { + if (sel.type != 'Control') { + range = sel.createRange(); + range.collapse(true); + x = range.boundingLeft; + y = range.boundingTop; + } + } else if (window.getSelection) { + sel = window.getSelection(); + + if (sel.rangeCount) { + range = sel.getRangeAt(0).cloneRange(); + if (range.getClientRects) { + range.collapse(true); + var rect = range.getClientRects()[0]; + + if (!rect) { + return; + } + + x = rect.left; + y = rect.top; + } + } + } + return { x: x, y: y }; + }; + + /** + * @private + * + * Returns selected text as String + * @returns {string} + */ + inline.getSelectionText = function () { + var selectedText = ''; + + // all modern browsers and IE9+ + if (window.getSelection) { + selectedText = window.getSelection().toString(); + } + + return selectedText; + }; + + /** Opens buttons block */ + inline.showButtons = function () { + var buttons = editor.nodes.inlineToolbar.buttons; + + buttons.classList.add('opened'); + + editor.toolbar.inline.buttonsOpened = true; + + /** highlight buttons */ + editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); + }; + + /** Makes buttons disappear */ + inline.closeButtons = function () { + var buttons = editor.nodes.inlineToolbar.buttons; + + buttons.classList.remove('opened'); + + editor.toolbar.inline.buttonsOpened = false; + }; + + /** Open buttons defined action if exist */ + inline.showActions = function () { + var action = editor.nodes.inlineToolbar.actions; + + action.classList.add('opened'); + + editor.toolbar.inline.actionsOpened = true; + }; + + /** Close actions block */ + inline.closeAction = function () { + var action = editor.nodes.inlineToolbar.actions; + + action.innerHTML = ''; + action.classList.remove('opened'); + editor.toolbar.inline.actionsOpened = false; + }; + + /** + * Callback for keydowns in inline toolbar "Insert link..." input + */ + var inlineToolbarAnchorInputKeydown_ = function inlineToolbarAnchorInputKeydown_(event) { + if (event.keyCode != editor.core.keys.ENTER) { + return; + } + + var editable = editor.content.currentNode, + storedSelection = editor.toolbar.inline.storedSelection; + + editor.toolbar.inline.restoreSelection(editable, storedSelection); + editor.toolbar.inline.setAnchor(this.value); + + /** + * Preventing events that will be able to happen + */ + event.preventDefault(); + event.stopImmediatePropagation(); + + editor.toolbar.inline.clearRange(); + }; + + /** Action for link creation or for setting anchor */ + inline.createLinkAction = function (event) { + var isActive = this.isLinkActive(); + + var editable = editor.content.currentNode, + storedSelection = editor.toolbar.inline.saveSelection(editable); + + /** Save globally selection */ + editor.toolbar.inline.storedSelection = storedSelection; + + if (isActive) { + /** + * Changing stored selection. if we want to remove anchor from word + * we should remove anchor from whole word, not only selected part. + * The solution is than we get the length of current link + * Change start position to - end of selection minus length of anchor + */ + editor.toolbar.inline.restoreSelection(editable, storedSelection); + + editor.toolbar.inline.defaultToolAction('unlink'); + } else { + /** Create input and close buttons */ + var action = editor.draw.inputForLink(); + + editor.nodes.inlineToolbar.actions.appendChild(action); + + editor.toolbar.inline.closeButtons(); + editor.toolbar.inline.showActions(); + + /** + * focus to input + * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus + * Prevents event after showing input and when we need to focus an input which is in unexisted form + */ + action.focus(); + event.preventDefault(); + + /** Callback to link action */ + editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false); + } + }; + + inline.isLinkActive = function () { + var isActive = false; + + editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) { + var dataType = tool.dataset.type; + + if (dataType == 'link' && tool.classList.contains('hightlighted')) { + isActive = true; + } + }); + + return isActive; + }; + + /** default action behavior of tool */ + inline.defaultToolAction = function (type) { + document.execCommand(type, false, null); + }; + + /** + * @private + * + * Sets URL + * + * @param {String} url - URL + */ + inline.setAnchor = function (url) { + document.execCommand('createLink', false, url); + + /** Close after URL inserting */ + editor.toolbar.inline.closeAction(); + }; + + /** + * @private + * + * Saves selection + */ + inline.saveSelection = function (containerEl) { + var range = window.getSelection().getRangeAt(0), + preSelectionRange = range.cloneRange(), + start; + + preSelectionRange.selectNodeContents(containerEl); + preSelectionRange.setEnd(range.startContainer, range.startOffset); + + start = preSelectionRange.toString().length; + + return { + start: start, + end: start + range.toString().length + }; + }; + + /** + * @private + * + * Sets to previous selection (Range) + * + * @param {Element} containerEl - editable element where we restore range + * @param {Object} savedSel - range basic information to restore + */ + inline.restoreSelection = function (containerEl, savedSel) { + var range = document.createRange(), + charIndex = 0; + + range.setStart(containerEl, 0); + range.collapse(true); + + var nodeStack = [containerEl], + node, + foundStart = false, + stop = false, + nextCharIndex; + + while (!stop && (node = nodeStack.pop())) { + if (node.nodeType == 3) { + nextCharIndex = charIndex + node.length; + + if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) { + range.setStart(node, savedSel.start - charIndex); + foundStart = true; + } + if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) { + range.setEnd(node, savedSel.end - charIndex); + stop = true; + } + charIndex = nextCharIndex; + } else { + var i = node.childNodes.length; + + while (i--) { + nodeStack.push(node.childNodes[i]); + } + } + } + + var sel = window.getSelection(); + + sel.removeAllRanges(); + sel.addRange(range); + }; + + /** + * @private + * + * Removes all ranges from window selection + */ + inline.clearRange = function () { + var selection = window.getSelection(); + + selection.removeAllRanges(); + }; + + /** + * @private + * + * sets or removes hightlight + */ + inline.hightlight = function (tool) { + var dataType = tool.dataset.type; + + if (document.queryCommandState(dataType)) { + editor.toolbar.inline.setButtonHighlighted(tool); + } else { + editor.toolbar.inline.removeButtonsHighLight(tool); + } + + /** + * + * hightlight for anchors + */ + var selection = window.getSelection(), + tag = selection.anchorNode.parentNode; + + if (tag.tagName == 'A' && dataType == 'link') { + editor.toolbar.inline.setButtonHighlighted(tool); + } + }; + + /** + * @private + * + * Mark button if text is already executed + */ + inline.setButtonHighlighted = function (button) { + button.classList.add('hightlighted'); + + /** At link tool we also change icon */ + if (button.dataset.type == 'link') { + var icon = button.childNodes[0]; + + icon.classList.remove('ce-icon-link'); + icon.classList.add('ce-icon-unlink'); + } + }; + + /** + * @private + * + * Removes hightlight + */ + inline.removeButtonsHighLight = function (button) { + button.classList.remove('hightlighted'); + + /** At link tool we also change icon */ + if (button.dataset.type == 'link') { + var icon = button.childNodes[0]; + + icon.classList.remove('ce-icon-unlink'); + icon.classList.add('ce-icon-link'); + } + }; + + return inline; +}({}); + +/***/ }), + +/***/ "./src/components/modules/toolbar/settings.js": +/*!****************************************************!*\ + !*** ./src/components/modules/toolbar/settings.js ***! + \****************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Toolbar settings + * + * @version 1.0.5 + */ + +module.exports = function (settings) { + var editor = codex.editor; + + settings.opened = false; + + settings.setting = null; + settings.actions = null; + + /** + * Append and open settings + */ + settings.open = function (toolType) { + /** + * Append settings content + * It's stored in tool.settings + */ + if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings) { + return; + } + + /** + * Draw settings block + */ + var settingsBlock = editor.tools[toolType].makeSettings(); + + editor.nodes.pluginSettings.appendChild(settingsBlock); + + /** Open settings block */ + editor.nodes.blockSettings.classList.add('opened'); + this.opened = true; + }; + + /** + * Close and clear settings + */ + settings.close = function () { + editor.nodes.blockSettings.classList.remove('opened'); + editor.nodes.pluginSettings.innerHTML = ''; + + this.opened = false; + }; + + /** + * @param {string} toolType - plugin type + */ + settings.toggle = function (toolType) { + if (!this.opened) { + this.open(toolType); + } else { + this.close(); + } + }; + + /** + * Here we will draw buttons and add listeners to components + */ + settings.makeRemoveBlockButton = function () { + var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}), + settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML: '' }), + actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}), + confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent: 'Удалить блок' }), + cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent: 'Отмена' }); + + editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false); + + editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false); + + editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false); + + actionWrapper.appendChild(confirmAction); + actionWrapper.appendChild(cancelAction); + + removeBlockWrapper.appendChild(settingButton); + removeBlockWrapper.appendChild(actionWrapper); + + /** Save setting */ + editor.toolbar.settings.setting = settingButton; + editor.toolbar.settings.actions = actionWrapper; + + return removeBlockWrapper; + }; + + settings.removeButtonClicked = function () { + var action = editor.toolbar.settings.actions; + + if (action.classList.contains('opened')) { + editor.toolbar.settings.hideRemoveActions(); + } else { + editor.toolbar.settings.showRemoveActions(); + } + + editor.toolbar.toolbox.close(); + editor.toolbar.settings.close(); + }; + + settings.cancelRemovingRequest = function () { + editor.toolbar.settings.actions.classList.remove('opened'); + }; + + settings.confirmRemovingRequest = function () { + var currentBlock = editor.content.currentNode, + firstLevelBlocksCount; + + currentBlock.remove(); + + firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; + + /** + * If all blocks are removed + */ + if (firstLevelBlocksCount === 0) { + /** update currentNode variable */ + editor.content.currentNode = null; + + /** Inserting new empty initial block */ + editor.ui.addInitialBlock(); + } + + editor.ui.saveInputs(); + + editor.toolbar.close(); + }; + + settings.showRemoveActions = function () { + editor.toolbar.settings.actions.classList.add('opened'); + }; + + settings.hideRemoveActions = function () { + editor.toolbar.settings.actions.classList.remove('opened'); + }; + + return settings; +}({}); + +/***/ }), + +/***/ "./src/components/modules/toolbar/toolbar.js": +/*!***************************************************!*\ + !*** ./src/components/modules/toolbar/toolbar.js ***! + \***************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Codex Editor toolbar module + * + * Contains: + * - Inline toolbox + * - Toolbox within plus button + * - Settings section + * + * @author Codex Team + * @version 1.0 + */ + +module.exports = function (toolbar) { + var editor = codex.editor; + + toolbar.settings = __webpack_require__(/*! ./settings */ "./src/components/modules/toolbar/settings.js"); + toolbar.inline = __webpack_require__(/*! ./inline */ "./src/components/modules/toolbar/inline.js"); + toolbar.toolbox = __webpack_require__(/*! ./toolbox */ "./src/components/modules/toolbar/toolbox.js"); + + /** + * Margin between focused node and toolbar + */ + toolbar.defaultToolbarHeight = 49; + + toolbar.defaultOffset = 34; + + toolbar.opened = false; + + toolbar.current = null; + + /** + * @protected + */ + toolbar.open = function () { + if (editor.hideToolbar) { + return; + } + + var toolType = editor.content.currentNode.dataset.tool; + + if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings) { + editor.nodes.showSettingsButton.classList.add('hide'); + } else { + editor.nodes.showSettingsButton.classList.remove('hide'); + } + + editor.nodes.toolbar.classList.add('opened'); + this.opened = true; + }; + + /** + * @protected + */ + toolbar.close = function () { + editor.nodes.toolbar.classList.remove('opened'); + + toolbar.opened = false; + toolbar.current = null; + + for (var button in editor.nodes.toolbarButtons) { + editor.nodes.toolbarButtons[button].classList.remove('selected'); + } + + /** Close toolbox when toolbar is not displayed */ + editor.toolbar.toolbox.close(); + editor.toolbar.settings.close(); + }; + + toolbar.toggle = function () { + if (!this.opened) { + this.open(); + } else { + this.close(); + } + }; + + toolbar.hidePlusButton = function () { + editor.nodes.plusButton.classList.add('hide'); + }; + + toolbar.showPlusButton = function () { + editor.nodes.plusButton.classList.remove('hide'); + }; + + /** + * Moving toolbar to the specified node + */ + toolbar.move = function () { + /** Close Toolbox when we move toolbar */ + editor.toolbar.toolbox.close(); + + if (!editor.content.currentNode) { + return; + } + + var newYCoordinate = editor.content.currentNode.offsetTop - editor.toolbar.defaultToolbarHeight / 2 + editor.toolbar.defaultOffset; + + editor.nodes.toolbar.style.transform = 'translate3D(0, ' + Math.floor(newYCoordinate) + 'px, 0)'; + + /** Close trash actions */ + editor.toolbar.settings.hideRemoveActions(); + }; + + return toolbar; +}({}); + +/***/ }), + +/***/ "./src/components/modules/toolbar/toolbox.js": +/*!***************************************************!*\ + !*** ./src/components/modules/toolbar/toolbox.js ***! + \***************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Codex Editor toolbox + * + * All tools be able to appended here + * + * @author Codex Team + * @version 1.0 + */ + +module.exports = function (toolbox) { + var editor = codex.editor; + + toolbox.opened = false; + toolbox.openedOnBlock = null; + + /** Shows toolbox */ + toolbox.open = function () { + /** Close setting if toolbox is opened */ + if (editor.toolbar.settings.opened) { + editor.toolbar.settings.close(); + } + + /** Add 'toolbar-opened' class for current block **/ + toolbox.openedOnBlock = editor.content.currentNode; + toolbox.openedOnBlock.classList.add('toolbar-opened'); + + /** display toolbox */ + editor.nodes.toolbox.classList.add('opened'); + + /** Animate plus button */ + editor.nodes.plusButton.classList.add('clicked'); + + /** toolbox state */ + editor.toolbar.toolbox.opened = true; + }; + + /** Closes toolbox */ + toolbox.close = function () { + /** Remove 'toolbar-opened' class from current block **/ + if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened'); + toolbox.openedOnBlock = null; + + /** Makes toolbox disappear */ + editor.nodes.toolbox.classList.remove('opened'); + + /** Rotate plus button */ + editor.nodes.plusButton.classList.remove('clicked'); + + /** toolbox state */ + editor.toolbar.toolbox.opened = false; + + editor.toolbar.current = null; + }; + + toolbox.leaf = function () { + var currentTool = editor.toolbar.current, + tools = Object.keys(editor.tools), + barButtons = editor.nodes.toolbarButtons, + nextToolIndex = 0, + toolToSelect = void 0, + visibleTool = void 0, + tool = void 0; + + if (!currentTool) { + /** Get first tool from object*/ + for (tool in editor.tools) { + if (editor.tools[tool].displayInToolbox) { + break; + } + + nextToolIndex++; + } + } else { + nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length; + visibleTool = tools[nextToolIndex]; + + while (!editor.tools[visibleTool].displayInToolbox) { + nextToolIndex = (nextToolIndex + 1) % tools.length; + visibleTool = tools[nextToolIndex]; + } + } + + toolToSelect = tools[nextToolIndex]; + + for (var button in barButtons) { + barButtons[button].classList.remove('selected'); + } + + barButtons[toolToSelect].classList.add('selected'); + editor.toolbar.current = toolToSelect; + }; + + /** + * Transforming selected node type into selected toolbar element type + * @param {event} event + */ + toolbox.toolClicked = function (event) { + /** + * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty + */ + var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'], + tool = editor.tools[editor.toolbar.current], + workingNode = editor.content.currentNode, + currentInputIndex = editor.caret.inputIndex, + newBlockContent, + appendCallback, + blockData; + + /** Make block from plugin */ + newBlockContent = tool.render(); + + /** information about block */ + blockData = { + block: newBlockContent, + type: tool.type, + stretched: false + }; + + if (workingNode && UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 && workingNode.textContent.trim() === '') { + /** Replace current block */ + editor.content.switchBlock(workingNode, newBlockContent, tool.type); + } else { + /** Insert new Block from plugin */ + editor.content.insertBlock(blockData); + + /** increase input index */ + currentInputIndex++; + } + + /** Fire tool append callback */ + appendCallback = tool.appendCallback; + + if (appendCallback && typeof appendCallback == 'function') { + appendCallback.call(event); + } + + window.setTimeout(function () { + /** Set caret to current block */ + editor.caret.setToBlock(currentInputIndex); + }, 10); + + /** + * Changing current Node + */ + editor.content.workingNodeChanged(); + + /** + * Move toolbar when node is changed + */ + editor.toolbar.move(); + }; + + return toolbox; +}({}); + +/***/ }), + /***/ "./src/components/modules/tools.js": /*!*****************************************!*\ !*** ./src/components/modules/tools.js ***! @@ -7285,7 +11032,7 @@ var UI = function (_Module) { /** * - /** Update current input index in memory when caret focused into existed input */ + /** Update current input index in memory when caret focused into existed input */ // if (event.target.contentEditable == 'true') { // // editor.caret.saveCurrentInputIndex(); @@ -8218,7 +11965,7 @@ exports = module.exports = __webpack_require__(/*! ../../node_modules/css-loader // module -exports.push([module.i, ":root {\n /**\n * Toolbar buttons\n */\n --bg-light: #eff2f5;\n\n /**\n * All gray texts: placeholders, settings\n */\n --grayText: #707684;\n\n /** Blue icons */\n --color-active-icon: #388AE5;\n\n /**\n * Block content width\n */\n --content-width: 650px;\n\n /**\n * Toolbar Plus Button and Toolbox buttons height and width\n */\n --toolbar-buttons-size: 34px;\n\n /**\n * Confirm deletion bg\n */\n --color-confirm: #E24A4A;\n}\n/**\n* Editor wrapper\n*/\n.codex-editor {\n position: relative;\n box-sizing: border-box;\n\n\n}\n.codex-editor .hide {\n display: none;\n }\n.codex-editor__redactor {\n padding-bottom: 300px;\n }\n.codex-editor svg {\n fill: currentColor;\n vertical-align: middle;\n max-height: 100%;\n }\n::-moz-selection{\n background-color: rgba(61,166,239,0.63);\n}\n::selection{\n background-color: rgba(61,166,239,0.63);\n}\n.ce-tune-moveup{}\n.ce-settings-delete:hover {\n cursor: pointer;\n }\n.ce-settings-delete::before {\n content: 'delete'\n }\n.ce-toolbar {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n /*opacity: 0;*/\n /*visibility: hidden;*/\n transition: opacity 100ms ease;\n will-change: opacity, transform;\n display: none;\n}\n.ce-toolbar--opened {\n display: block;\n /*opacity: 1;*/\n /*visibility: visible;*/\n }\n.ce-toolbar__content {\n max-width: 650px;\n max-width: var(--content-width);\n margin: 0 auto;\n position: relative;\n }\n.ce-toolbar__plus {\n position: absolute;\n left: calc(calc(34px + 10px) * -1);\n left: calc(calc(var(--toolbar-buttons-size) + 10px) * -1);\n display: inline-block;\n background-color: #eff2f5;\n background-color: var(--bg-light);\n width: 34px;\n width: var(--toolbar-buttons-size);\n height: 34px;\n height: var(--toolbar-buttons-size);\n line-height: 34px;\n text-align: center;\n border-radius: 50%;\n cursor: pointer;\n }\n.ce-toolbar__plus--hidden {\n display: none;\n }\n/**\n * Block actions Zone\n * -------------------------\n */\n.ce-toolbar__actions {\n position: absolute;\n right: 0;\n top: 0;\n padding-right: 16px;\n }\n.ce-toolbar__actions-buttons {\n text-align: right;\n }\n.ce-toolbar__settings-btn {\n display: inline-block;\n width: 24px;\n height: 24px;\n color: #707684;\n color: var(--grayText);\n cursor: pointer;\n }\n.ce-toolbox {\n position: absolute;\n visibility: hidden;\n transition: opacity 100ms ease;\n will-change: opacity;\n}\n.ce-toolbox--opened {\n opacity: 1;\n visibility: visible;\n }\n.ce-toolbox__button {\n display: inline-block;\n list-style: none;\n margin: 0;\n background: #eff2f5;\n background: var(--bg-light);\n width: 34px;\n width: var(--toolbar-buttons-size);\n height: 34px;\n height: var(--toolbar-buttons-size);\n border-radius: 30px;\n overflow: hidden;\n text-align: center;\n line-height: 34px;\n line-height: var(--toolbar-buttons-size)\n }\n.ce-toolbox__button::before {\n content: attr(title);\n font-size: 22px;\n font-weight: 500;\n letter-spacing: 1em;\n -webkit-font-feature-settings: \"smcp\", \"c2sc\";\n font-feature-settings: \"smcp\", \"c2sc\";\n font-variant-caps: all-small-caps;\n padding-left: 11.5px;\n margin-top: -1px;\n display: inline-block;\n }\n.ce-inline-toolbar {\n position: absolute;\n background-color: #FFFFFF;\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\n border-radius: 4px;\n z-index: 2\n}\n.ce-inline-toolbar::before {\n content: '';\n width: 15px;\n height: 15px;\n position: absolute;\n top: -7px;\n left: 50%;\n margin-left: -7px;\n transform: rotate(-45deg);\n background-color: #fff;\n z-index: -1;\n }\n.ce-inline-toolbar {\n padding: 6px;\n transform: translateX(-50%);\n display: none;\n box-shadow: 0 6px 12px -6px rgba(131, 147, 173, 0.46),\n 5px -12px 34px -13px rgba(97, 105, 134, 0.6),\n 0 26px 52px 3px rgba(147, 165, 186, 0.24);\n}\n.ce-inline-toolbar--showed {\n display: block;\n }\n.ce-inline-tool {\n display: inline-block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n border-radius: 3px;\n cursor: pointer;\n border: 0;\n outline: none;\n background-color: transparent;\n vertical-align: bottom;\n color: #707684;\n color: var(--grayText)\n}\n.ce-inline-tool:not(:last-of-type){\n margin-right: 5px;\n }\n.ce-inline-tool:hover {\n background-color: #eff2f5;\n background-color: var(--bg-light);\n }\n.ce-inline-tool {\n line-height: normal;\n}\n.ce-inline-tool--active {\n color: #388AE5;\n color: var(--color-active-icon);\n }\n.ce-inline-tool--link .icon {\n margin-top: -2px;\n }\n.ce-inline-tool--link .icon--unlink {\n display: none;\n }\n.ce-inline-tool--unlink .icon--link {\n display: none;\n }\n.ce-inline-tool--unlink .icon--unlink {\n display: inline-block;\n }\n.ce-inline-tool-input {\n background-color: #eff2f5;\n background-color: var(--bg-light);\n outline: none;\n border: 0;\n border-radius: 3px;\n margin: 6px 0 0;\n font-size: 13px;\n padding: 8px;\n width: 100%;\n box-sizing: border-box;\n display: none\n }\n.ce-inline-tool-input::-webkit-input-placeholder {\n color: #707684;\n color: var(--grayText);\n }\n.ce-inline-tool-input:-ms-input-placeholder {\n color: #707684;\n color: var(--grayText);\n }\n.ce-inline-tool-input::placeholder {\n color: #707684;\n color: var(--grayText);\n }\n.ce-inline-tool-input--showed {\n display: block;\n }\n.ce-settings {\n position: absolute;\n background-color: #FFFFFF;\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\n border-radius: 4px;\n z-index: 2\n}\n.ce-settings::before {\n content: '';\n width: 15px;\n height: 15px;\n position: absolute;\n top: -7px;\n left: 50%;\n margin-left: -7px;\n transform: rotate(-45deg);\n background-color: #fff;\n z-index: -1;\n }\n.ce-settings {\n right: 5px;\n top: 35px;\n min-width: 124px\n}\n.ce-settings::before{\n left: auto;\n right: 12px;\n }\n.ce-settings {\n\n display: none;\n}\n.ce-settings--opened {\n display: block;\n }\n.ce-settings__plugin-zone:not(:empty){\n padding: 6px;\n }\n.ce-settings__default-zone:not(:empty){\n padding: 6px;\n }\n.ce-settings__button {\n display: inline-block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n border-radius: 3px;\n cursor: pointer;\n border: 0;\n outline: none;\n background-color: transparent;\n vertical-align: bottom;\n color: #707684;\n color: var(--grayText)\n }\n.ce-settings__button:not(:last-of-type){\n margin-right: 5px;\n }\n.ce-settings__button:hover {\n background-color: #eff2f5;\n background-color: var(--bg-light);\n }\n.ce-settings__button--active {\n color: #388AE5;\n color: var(--color-active-icon);\n }\n.ce-settings__button--delete {\n transition: background-color 300ms ease;\n will-change: background-color;\n }\n.ce-settings__button--delete .icon {\n transition: transform 200ms ease-out;\n will-change: transform;\n }\n.ce-settings__button--confirm {\n background-color: #E24A4A;\n background-color: var(--color-confirm);\n color: #fff\n }\n.ce-settings__button--confirm:hover {\n background-color: rgb(213, 74, 74) !important;\n background-color: rgb(213, 74, 74) !important;\n }\n.ce-settings__button--confirm .icon {\n transform: rotate(90deg);\n }\n.ce-settings-move-up:hover {\n cursor: pointer;\n }\n.ce-settings-move-up--disabled {\n cursor: not-allowed !important;\n opacity: .3;\n }\n.ce-block:first-of-type {\n margin-top: 0;\n }\n.ce-block--selected {\n background-image: linear-gradient(17deg, rgba(243, 248, 255, 0.03) 63.45%, rgba(207, 214, 229, 0.27) 98%);\n border-radius: 3px;\n }\n.ce-block__content {\n max-width: 650px;\n max-width: var(--content-width);\n margin: 0 auto;\n }\n", ""]); +exports.push([module.i, ":root {\r\n /**\r\n * Toolbar buttons\r\n */\r\n --bg-light: #eff2f5;\r\n\r\n /**\r\n * All gray texts: placeholders, settings\r\n */\r\n --grayText: #707684;\r\n\r\n /** Blue icons */\r\n --color-active-icon: #388AE5;\r\n\r\n /**\r\n * Block content width\r\n */\r\n --content-width: 650px;\r\n\r\n /**\r\n * Toolbar Plus Button and Toolbox buttons height and width\r\n */\r\n --toolbar-buttons-size: 34px;\r\n\r\n /**\r\n * Confirm deletion bg\r\n */\r\n --color-confirm: #E24A4A;\r\n}\r\n/**\r\n* Editor wrapper\r\n*/\r\n.codex-editor {\r\n position: relative;\r\n box-sizing: border-box;\r\n\r\n\r\n}\r\n.codex-editor .hide {\r\n display: none;\r\n }\r\n.codex-editor__redactor {\r\n padding-bottom: 300px;\r\n }\r\n.codex-editor svg {\r\n fill: currentColor;\r\n vertical-align: middle;\r\n max-height: 100%;\r\n }\r\n::-moz-selection{\r\n background-color: rgba(61,166,239,0.63);\r\n}\r\n::selection{\r\n background-color: rgba(61,166,239,0.63);\r\n}\r\n.ce-tune-moveup{}\r\n.ce-settings-delete:hover {\r\n cursor: pointer;\r\n }\r\n.ce-settings-delete::before {\r\n content: 'delete'\r\n }\r\n.ce-toolbar {\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n top: 0;\r\n /*opacity: 0;*/\r\n /*visibility: hidden;*/\r\n transition: opacity 100ms ease;\r\n will-change: opacity, transform;\r\n display: none;\r\n}\r\n.ce-toolbar--opened {\r\n display: block;\r\n /*opacity: 1;*/\r\n /*visibility: visible;*/\r\n }\r\n.ce-toolbar__content {\r\n max-width: 650px;\r\n max-width: var(--content-width);\r\n margin: 0 auto;\r\n position: relative;\r\n }\r\n.ce-toolbar__plus {\r\n position: absolute;\r\n left: calc(calc(34px + 10px) * -1);\r\n left: calc(calc(var(--toolbar-buttons-size) + 10px) * -1);\r\n display: inline-block;\r\n background-color: #eff2f5;\r\n background-color: var(--bg-light);\r\n width: 34px;\r\n width: var(--toolbar-buttons-size);\r\n height: 34px;\r\n height: var(--toolbar-buttons-size);\r\n line-height: 34px;\r\n text-align: center;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n }\r\n.ce-toolbar__plus--hidden {\r\n display: none;\r\n }\r\n/**\r\n * Block actions Zone\r\n * -------------------------\r\n */\r\n.ce-toolbar__actions {\r\n position: absolute;\r\n right: 0;\r\n top: 0;\r\n padding-right: 16px;\r\n }\r\n.ce-toolbar__actions-buttons {\r\n text-align: right;\r\n }\r\n.ce-toolbar__settings-btn {\r\n display: inline-block;\r\n width: 24px;\r\n height: 24px;\r\n color: #707684;\r\n color: var(--grayText);\r\n cursor: pointer;\r\n }\r\n.ce-toolbox {\r\n position: absolute;\r\n visibility: hidden;\r\n transition: opacity 100ms ease;\r\n will-change: opacity;\r\n}\r\n.ce-toolbox--opened {\r\n opacity: 1;\r\n visibility: visible;\r\n }\r\n.ce-toolbox__button {\r\n display: inline-block;\r\n list-style: none;\r\n margin: 0;\r\n background: #eff2f5;\r\n background: var(--bg-light);\r\n width: 34px;\r\n width: var(--toolbar-buttons-size);\r\n height: 34px;\r\n height: var(--toolbar-buttons-size);\r\n border-radius: 30px;\r\n overflow: hidden;\r\n text-align: center;\r\n line-height: 34px;\r\n line-height: var(--toolbar-buttons-size)\r\n }\r\n.ce-toolbox__button::before {\r\n content: attr(title);\r\n font-size: 22px;\r\n font-weight: 500;\r\n letter-spacing: 1em;\r\n -webkit-font-feature-settings: \"smcp\", \"c2sc\";\r\n font-feature-settings: \"smcp\", \"c2sc\";\r\n font-variant-caps: all-small-caps;\r\n padding-left: 11.5px;\r\n margin-top: -1px;\r\n display: inline-block;\r\n }\r\n.ce-inline-toolbar {\r\n position: absolute;\r\n background-color: #FFFFFF;\r\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\r\n border-radius: 4px;\r\n z-index: 2\r\n}\r\n.ce-inline-toolbar::before {\r\n content: '';\r\n width: 15px;\r\n height: 15px;\r\n position: absolute;\r\n top: -7px;\r\n left: 50%;\r\n margin-left: -7px;\r\n transform: rotate(-45deg);\r\n background-color: #fff;\r\n z-index: -1;\r\n }\r\n.ce-inline-toolbar {\r\n padding: 6px;\r\n transform: translateX(-50%);\r\n display: none;\r\n box-shadow: 0 6px 12px -6px rgba(131, 147, 173, 0.46),\r\n 5px -12px 34px -13px rgba(97, 105, 134, 0.6),\r\n 0 26px 52px 3px rgba(147, 165, 186, 0.24);\r\n}\r\n.ce-inline-toolbar--showed {\r\n display: block;\r\n }\r\n.ce-inline-tool {\r\n display: inline-block;\r\n width: 34px;\r\n height: 34px;\r\n line-height: 34px;\r\n text-align: center;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n border: 0;\r\n outline: none;\r\n background-color: transparent;\r\n vertical-align: bottom;\r\n color: #707684;\r\n color: var(--grayText)\r\n}\r\n.ce-inline-tool:not(:last-of-type){\r\n margin-right: 5px;\r\n }\r\n.ce-inline-tool:hover {\r\n background-color: #eff2f5;\r\n background-color: var(--bg-light);\r\n }\r\n.ce-inline-tool {\r\n line-height: normal;\r\n}\r\n.ce-inline-tool--active {\r\n color: #388AE5;\r\n color: var(--color-active-icon);\r\n }\r\n.ce-inline-tool--link .icon {\r\n margin-top: -2px;\r\n }\r\n.ce-inline-tool--link .icon--unlink {\r\n display: none;\r\n }\r\n.ce-inline-tool--unlink .icon--link {\r\n display: none;\r\n }\r\n.ce-inline-tool--unlink .icon--unlink {\r\n display: inline-block;\r\n }\r\n.ce-inline-tool-input {\r\n background-color: #eff2f5;\r\n background-color: var(--bg-light);\r\n outline: none;\r\n border: 0;\r\n border-radius: 3px;\r\n margin: 6px 0 0;\r\n font-size: 13px;\r\n padding: 8px;\r\n width: 100%;\r\n box-sizing: border-box;\r\n display: none\r\n }\r\n.ce-inline-tool-input::-webkit-input-placeholder {\r\n color: #707684;\r\n color: var(--grayText);\r\n }\r\n.ce-inline-tool-input:-ms-input-placeholder {\r\n color: #707684;\r\n color: var(--grayText);\r\n }\r\n.ce-inline-tool-input::placeholder {\r\n color: #707684;\r\n color: var(--grayText);\r\n }\r\n.ce-inline-tool-input--showed {\r\n display: block;\r\n }\r\n.ce-settings {\r\n position: absolute;\r\n background-color: #FFFFFF;\r\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\r\n border-radius: 4px;\r\n z-index: 2\r\n}\r\n.ce-settings::before {\r\n content: '';\r\n width: 15px;\r\n height: 15px;\r\n position: absolute;\r\n top: -7px;\r\n left: 50%;\r\n margin-left: -7px;\r\n transform: rotate(-45deg);\r\n background-color: #fff;\r\n z-index: -1;\r\n }\r\n.ce-settings {\r\n right: 5px;\r\n top: 35px;\r\n min-width: 124px\r\n}\r\n.ce-settings::before{\r\n left: auto;\r\n right: 12px;\r\n }\r\n.ce-settings {\r\n\r\n display: none;\r\n}\r\n.ce-settings--opened {\r\n display: block;\r\n }\r\n.ce-settings__plugin-zone:not(:empty){\r\n padding: 6px;\r\n }\r\n.ce-settings__default-zone:not(:empty){\r\n padding: 6px;\r\n }\r\n.ce-settings__button {\r\n display: inline-block;\r\n width: 34px;\r\n height: 34px;\r\n line-height: 34px;\r\n text-align: center;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n border: 0;\r\n outline: none;\r\n background-color: transparent;\r\n vertical-align: bottom;\r\n color: #707684;\r\n color: var(--grayText)\r\n }\r\n.ce-settings__button:not(:last-of-type){\r\n margin-right: 5px;\r\n }\r\n.ce-settings__button:hover {\r\n background-color: #eff2f5;\r\n background-color: var(--bg-light);\r\n }\r\n.ce-settings__button--active {\r\n color: #388AE5;\r\n color: var(--color-active-icon);\r\n }\r\n.ce-settings__button--delete {\r\n transition: background-color 300ms ease;\r\n will-change: background-color;\r\n }\r\n.ce-settings__button--delete .icon {\r\n transition: transform 200ms ease-out;\r\n will-change: transform;\r\n }\r\n.ce-settings__button--confirm {\r\n background-color: #E24A4A;\r\n background-color: var(--color-confirm);\r\n color: #fff\r\n }\r\n.ce-settings__button--confirm:hover {\r\n background-color: rgb(213, 74, 74) !important;\r\n background-color: rgb(213, 74, 74) !important;\r\n }\r\n.ce-settings__button--confirm .icon {\r\n transform: rotate(90deg);\r\n }\r\n.ce-settings-move-up:hover {\r\n cursor: pointer;\r\n }\r\n.ce-settings-move-up--disabled {\r\n cursor: not-allowed !important;\r\n opacity: .3;\r\n }\r\n.ce-block:first-of-type {\r\n margin-top: 0;\r\n }\r\n.ce-block--selected {\r\n background-image: linear-gradient(17deg, rgba(243, 248, 255, 0.03) 63.45%, rgba(207, 214, 229, 0.27) 98%);\r\n border-radius: 3px;\r\n }\r\n.ce-block__content {\r\n max-width: 650px;\r\n max-width: var(--content-width);\r\n margin: 0 auto;\r\n }\r\n", ""]); // exports diff --git a/build/codex-editor.js.map b/build/codex-editor.js.map index aa78c8c9..aef6f48a 100644 --- a/build/codex-editor.js.map +++ b/build/codex-editor.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://CodexEditor/webpack/universalModuleDefinition","webpack://CodexEditor/webpack/bootstrap","webpack://CodexEditor/./build/sprite.svg","webpack://CodexEditor/./node_modules/css-loader/lib/css-base.js","webpack://CodexEditor/./node_modules/html-janitor/src/html-janitor.js","webpack://CodexEditor/./src/codex.js","webpack://CodexEditor/./src/components/__module.ts","webpack://CodexEditor/./src/components/block-tunes/block-tune-delete.ts","webpack://CodexEditor/./src/components/block-tunes/block-tune-move-up.ts","webpack://CodexEditor/./src/components/block.js","webpack://CodexEditor/./src/components/dom.js","webpack://CodexEditor/./src/components/inline-tools/inline-tool-bold.ts","webpack://CodexEditor/./src/components/inline-tools/inline-tool-italic.ts","webpack://CodexEditor/./src/components/inline-tools/inline-tool-link.ts","webpack://CodexEditor/./src/components/modules sync nonrecursive [^_](api-blocks.ts|api-events.ts|api-listener.ts|api-sanitizer.ts|api-saver.ts|api-selection.ts|api-toolbar.ts|api.ts|block-events.ts|blockManager.js|caret.js|events.js|listeners.js|renderer.js|sanitizer.js|saver.js|toolbar-blockSettings.js|toolbar-inline.ts|toolbar-toolbox.js|toolbar.js|tools.js|ui.js)$","webpack://CodexEditor/./src/components/modules/api-blocks.ts","webpack://CodexEditor/./src/components/modules/api-events.ts","webpack://CodexEditor/./src/components/modules/api-listener.ts","webpack://CodexEditor/./src/components/modules/api-sanitizer.ts","webpack://CodexEditor/./src/components/modules/api-saver.ts","webpack://CodexEditor/./src/components/modules/api-selection.ts","webpack://CodexEditor/./src/components/modules/api-toolbar.ts","webpack://CodexEditor/./src/components/modules/api.ts","webpack://CodexEditor/./src/components/modules/block-events.ts","webpack://CodexEditor/./src/components/modules/blockManager.js","webpack://CodexEditor/./src/components/modules/caret.js","webpack://CodexEditor/./src/components/modules/events.js","webpack://CodexEditor/./src/components/modules/listeners.js","webpack://CodexEditor/./src/components/modules/renderer.js","webpack://CodexEditor/./src/components/modules/sanitizer.js","webpack://CodexEditor/./src/components/modules/saver.js","webpack://CodexEditor/./src/components/modules/toolbar-blockSettings.js","webpack://CodexEditor/./src/components/modules/toolbar-inline.ts","webpack://CodexEditor/./src/components/modules/toolbar-toolbox.js","webpack://CodexEditor/./src/components/modules/toolbar.js","webpack://CodexEditor/./src/components/modules/tools.js","webpack://CodexEditor/./src/components/modules/ui.js","webpack://CodexEditor/./src/components/polyfills.js","webpack://CodexEditor/./src/components/selection.js","webpack://CodexEditor/./src/components/utils.js","webpack://CodexEditor/./src/styles/main.css"],"names":["modules","editorModules","map","module","CodexEditor","config","moduleInstances","Promise","resolve","then","configuration","init","start","methods","API","method","console","log","catch","error","constructModules","configureModules","forEach","Module","displayName","e","name","state","getModulesDiff","diff","moduleName","prepareDecorator","prepare","Tools","UI","BlockManager","Renderer","render","data","items","initialBlock","type","holderId","placeholder","sanitizer","p","b","a","hideToolbar","tools","toolsConfig","_","isEmpty","length","Editor","new","target","TypeError","DeleteTune","api","CSS","wrapper","button","buttonDelete","buttonConfirm","nodes","resetConfirmation","setConfirmation","$","make","appendChild","svg","listener","on","event","handleClick","needConfirmation","events","off","blocks","delete","classList","add","MoveUpTune","btnDisabled","moveUpButton","getCurrentBlockIndex","currentBlockIndex","currentBlockElement","getBlockByIndex","html","previousBlockElement","currentBlockCoords","getBoundingClientRect","previousBlockCoords","scrollUpOffset","top","Math","abs","window","innerHeight","scrollBy","swap","Block","toolName","toolInstance","settings","apiMethods","tool","_html","compose","tunes","makeTunes","contentNode","content","pluginsContent","methodName","params","Function","call","merge","extractedBlock","save","measuringStart","performance","now","measuringEnd","finishedExtraction","time","isValid","validate","tunesList","tune","tunesElement","document","createDocumentFragment","append","contentless","emptyText","emptyMedia","hasMedia","mediaTags","querySelector","join","selected","remove","Dom","tag","tagName","includes","classNames","attributes","el","createElement","Array","isArray","attrName","createTextNode","width","height","icon","createElementNS","setAttribute","innerHTML","parent","elements","el1","el2","temp","parentNode","insertBefore","removeChild","selector","querySelectorAll","node","atLast","child","sibling","nodeType","Node","ELEMENT_NODE","nodeChild","isSingleTag","getDeepestNode","nativeInputs","nodeText","isElement","isNativeInput","value","textContent","replace","trim","childNodes","treeWalker","leafs","isNodeEmpty","push","firstChild","shift","isLeaf","nextSibling","every","leaf","BoldInlineTool","commandName","buttonActive","buttonModifier","range","execCommand","selection","isActive","queryCommandState","toggle","ItalicInlineTool","LinkInlineTool","commandLink","commandUnlink","ENTER_KEY","buttonUnlink","input","inputShowed","inputOpened","inlineToolbar","toolbar","Selection","addEventListener","keyCode","enterPressed","parentAnchor","findParentTag","expandToTag","unlink","closeActions","checkState","close","toggleActions","anchorTag","openActions","hrefAttr","getAttribute","needFocus","focus","clearSavedSelection","clearSaved","restore","preventDefault","validateURL","prepareLink","insertLink","stopPropagation","stopImmediatePropagation","str","test","link","addProtocol","isInternal","isAnchor","substring","isProtocolRelative","BlocksAPI","index","fromIndex","toIndex","Toolbar","move","blockIndex","removeBlock","insert","Caret","setToBlock","currentBlock","navigatePrevious","clear","EventsAPI","eventName","callback","Events","emit","ListenerAPI","element","eventType","handler","useCapture","Listeners","SanitizerAPI","taintString","Sanitizer","clean","SaverAPI","Saver","SelectionAPI","className","ToolbarAPI","open","caret","saver","BlockEvents","keyCodes","BACKSPACE","backspace","ENTER","enter","DOWN","RIGHT","arrowRightAndDownPressed","UP","LEFT","arrowLeftAndUpPressed","InlineToolbar","handleShowingEvent","apiSettings","IS_ENABLED_LINE_BREAKS","shiftKey","split","newCurrent","isInitial","plusButton","show","BM","isFirstBlock","canMergeBlocks","isAtStart","targetBlock","blockToMerge","mergeable","setCaretToTheEnd","mergeBlocks","setTimeout","navigateNext","_blocks","Blocks","redactor","Proxy","set","get","construct","block","bindEvents","keydown","mouseUp","keyup","composeBlock","blockToMergeIndex","indexOf","blockToMergeInfo","mergeWith","extractedFragment","extractFragmentFromCaretPosition","text","blockInserted","currentNode","firstLevelBlock","closest","childNode","parentFirstLevelBlock","Error","needAddInitialBlock","removeAll","isLastBlock","array","workingArea","first","second","secondBlock","deleteCount","splice","previousBlock","insertAdjacentElement","nextBlock","isNaN","newBlock","children","instance","Number","offset","atEnd","nodeToSet","delay","createRange","setStart","setEnd","removeAllRanges","addRange","lastBlock","rangeCount","selectRange","getRangeAt","blockElem","deleteContents","cloneRange","selectNodeContents","endContainer","endOffset","extractContents","from","direction","current","siblings","contentEditable","force","isAtEnd","isCollapsed","anchorNode","firstNode","firstLetterPosition","search","leftSiblings","getHigherLevelSiblings","nothingAtLeft","anchorOffset","lastNode","nothingAtRight","rightTrimmedText","subscribers","reduce","previousData","currentHandler","newData","i","allListeners","assignedEventData","alreadyExist","findOne","existingListeners","findAll","removeEventListener","listenersOnElement","listenersWithType","listenersWithHandler","foundListeners","found","foundByElements","findByElement","filter","chainData","function","insertBlock","sequence","item","available","defaultConfig","_sanitizerInstance","sanitizerConfig","sanitizerInstance","require","customConfig","library","tags","href","rel","newInstance","output","blocksData","all","allExtractedData","makeOutput","outputData","totalTime","groupCollapsed","extraction","groupEnd","Date","version","VERSION","BlockSettings","toolSettings","defaultSettings","makeSettings","renderTunes","wrapperOpened","addToolSettings","addDefaultSettings","opened","closed","contains","inlineToolbarShowed","buttonsWrapper","actionsWrapper","buttons","actions","toolbarVerticalMargin","addTools","allowedToShow","checkToolsState","selectionRect","rect","wrapperOffset","newCoords","x","left","y","floor","style","tagsConflictsWithSelection","currentSelection","selectedText","getBlock","toolConfig","IS_ENABLED_INLINE_TOOLBAR","addTool","renderActions","toolClicked","surround","toolsInstances","inline","Tool","Toolbox","toolbox","toolsAvailable","IS_DISPLAYED_IN_TOOLBOX","TOOLBAR_ICON_CLASS","toolboxButton","title","dataset","buttonClicked","toolButton","toolClasses","IS_IRREPLACEBLE_TOOL","toolboxOpened","blockActionsButtons","settingsToggler","plusButtonClicked","settingsIcon","forceClose","defaultToolbarHeight","defaultOffset","newYCoordinate","offsetTop","transform","toolbarOpened","settingsTogglerClicked","hide","plusButtonHidden","toolsUnavailable","Object","values","IS_INLINE","inlineToolRequiredMethods","notImplementedMethods","hasOwnProperty","reject","sequenceData","getListOfPrepareFunctions","success","fallback","toolPreparationList","toolClass","plugin","holder","appendSVGSprite","loadStyles","getElementById","editorWrapper","editorZone","styles","toString","head","redactorClicked","documentClicked","clickedOnInlineToolbarButton","clickedNode","setCurrentBlockByChildNode","setToTheLastBlock","isInitialBlock","isEmptyBlock","spriteHolder","sprite","Element","prototype","matches","msMatchesSelector","webkitMatchesSelector","s","documentElement","parentElement","savedSelectionRange","sel","getSelection","searchDepth","parentTag","focusNode","boundNodes","searchDepthIterable","boundingLeft","boundingTop","boundingWidth","boundingHeight","span","insertNode","spanParent","normalize","Util","msg","args","chains","previousValue","currentValue","iteration","waitNextBlock","successCallback","fallbackCallback","collection","slice","object","keys","constructor","timeout","context","arguments","apply","TAB","SHIFT","CTRL","ALT","ESC","SPACE","DELETE","META"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;;;;;AClFA,4+H;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,mCAAmC,gBAAgB;AACnD,IAAI;AACJ;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,gBAAgB,iBAAiB;AACjC;AACA;AACA;AACA;AACA,YAAY,oBAAoB;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,oDAAoD,cAAc;;AAElE;AACA;;;;;;;;;;;;AC3EA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA,GAAG,QAIH;AACA,CAAC;;AAED;AACA,aAAa,OAAO;AACpB,aAAa,QAAQ;AACrB;AACA;;AAEA;AACA;;AAEA;AACA,wBAAwB,iCAAiC,EAAE;AAC3D,6BAA6B,uEAAuE,EAAE;;AAEtG;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,QAAQ;;AAExB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,+DAA+D;AAC/D;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,qBAAqB,4BAA4B;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;;AAEA,CAAC;;;;;;;;;;;;;ACxLD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCA;;;;AAIA;;;;;;;;;;;;AAYA;;;;;;;AAOA;;AAEA;;;;;;;;;;AAGA;;;;AAEA;;;AAGA;AACA,IAAIA,UAAU,wVAAAC,CAAcC,GAAd,CAAmB;AAAA,SAAU,2WAAQ,GAA0BC,MAAlC,CAAV;AAAA,CAAnB,CAAd;;AAEA;;;;;;;;;;;IAUqBC,W;;;;AACnB;wBACqB;AACnB,aAAO,OAAP;AACD;;AAED;;;;;;;AAIA,uBAAYC,MAAZ,EAAoB;AAAA;;AAAA;;AAClB;;;;AAIA,SAAKA,MAAL,GAAc,EAAd;;AAEA;;;;;;;;;;;;AAYA,SAAKC,eAAL,GAAuB,EAAvB;;AAEAC,YAAQC,OAAR,GACGC,IADH,CACQ,YAAM;AACV,YAAKC,aAAL,GAAqBL,MAArB;AACD,KAHH,EAIGI,IAJH,CAIQ;AAAA,aAAM,MAAKE,IAAL,EAAN;AAAA,KAJR,EAKGF,IALH,CAKQ;AAAA,aAAM,MAAKG,KAAL,EAAN;AAAA,KALR,EAMGH,IANH,CAMQ,YAAM;AACV,UAAII,UAAU,MAAKP,eAAL,CAAqBQ,GAArB,CAAyBD,OAAvC;;AAEA;;;AAGA,WAAK,IAAIE,MAAT,IAAmBF,OAAnB,EAA4B;AAC1B,cAAKE,MAAL,IAAeF,QAAQE,MAAR,CAAf;AACD;;AAED,aAAO,MAAKT,eAAZ,CAVU,CAUmB;AAC9B,KAjBH,EAkBGG,IAlBH,CAkBQ,YAAM;AACVO,cAAQC,GAAR,CAAY,wBAAZ;AACD,KApBH,EAqBGC,KArBH,CAqBS,iBAAS;AACdF,cAAQC,GAAR,CAAY,2CAAZ,EAAyDE,KAAzD;AACD,KAvBH;AAwBD;;AAED;;;;;;;;;;AA0DA;;;;;2BAKO;AACL;;;AAGA,WAAKC,gBAAL;;AAEA;;;AAGA,WAAKC,gBAAL;AACD;;AAED;;;;;;uCAGmB;AAAA;;AACjBrB,cAAQsB,OAAR,CAAiB,kBAAU;AACzB,YAAI;AACF;;;;;;;AAOA,iBAAKhB,eAAL,CAAqBiB,OAAOC,WAA5B,IAA2C,IAAID,MAAJ,CAAW;AACpDlB,oBAAS,OAAKK;AADsC,WAAX,CAA3C;AAGD,SAXD,CAWE,OAAQe,CAAR,EAAY;AACZT,kBAAQC,GAAR,CAAY,8BAAZ,EAA4CM,MAA5C,EAAoDE,CAApD;AACD;AACF,OAfD;AAgBD;;AAED;;;;;;;;uCAKmB;AACjB,WAAI,IAAIC,IAAR,IAAgB,KAAKpB,eAArB,EAAsC;AACpC;;;AAGA,aAAKA,eAAL,CAAqBoB,IAArB,EAA2BC,KAA3B,GAAmC,KAAKC,cAAL,CAAqBF,IAArB,CAAnC;AACD;AACF;;AAED;;;;;;mCAGgBA,I,EAAO;AACrB,UAAIG,OAAO,EAAX;;AAEA,WAAI,IAAIC,UAAR,IAAsB,KAAKxB,eAA3B,EAA4C;AAC1C;;;AAGA,YAAIwB,eAAeJ,IAAnB,EAAyB;AACvB;AACD;AACDG,aAAKC,UAAL,IAAmB,KAAKxB,eAAL,CAAqBwB,UAArB,CAAnB;AACD;;AAED,aAAOD,IAAP;AACD;;AAED;;;;;;;;;4BAMQ;AAAA;;AACN,UAAIE,mBAAmB,SAAnBA,gBAAmB;AAAA,eAAU5B,OAAO6B,OAAP,EAAV;AAAA,OAAvB;;AAEA,aAAOzB,QAAQC,OAAR,GACJC,IADI,CACCsB,iBAAiB,KAAKzB,eAAL,CAAqB2B,KAAtC,CADD,EAEJxB,IAFI,CAECsB,iBAAiB,KAAKzB,eAAL,CAAqB4B,EAAtC,CAFD,EAGJzB,IAHI,CAGCsB,iBAAiB,KAAKzB,eAAL,CAAqB6B,YAAtC,CAHD,EAIJ1B,IAJI,CAIC,YAAM;AACV,eAAO,OAAKH,eAAL,CAAqB8B,QAArB,CAA8BC,MAA9B,CAAqC,OAAKhC,MAAL,CAAYiC,IAAZ,CAAiBC,KAAtD,CAAP;AACD,OANI,CAAP;AAOD;;;sBA9IiBlC,M,EAAQ;AACxB;;;;;AAKA,UAAImC,eAAe;AACjBC,cAAOpC,OAAOmC,YADG;AAEjBF,cAAO;AAFU,OAAnB;;AAKA,WAAKjC,MAAL,CAAYqC,QAAZ,GAAuBrC,OAAOqC,QAA9B;AACA,WAAKrC,MAAL,CAAYsC,WAAZ,GAA0BtC,OAAOsC,WAAP,IAAsB,qBAAhD;AACA,WAAKtC,MAAL,CAAYuC,SAAZ,GAAwBvC,OAAOuC,SAAP,IAAoB;AAC1CC,WAAG,IADuC;AAE1CC,WAAG,IAFuC;AAG1CC,WAAG;AAHuC,OAA5C;;AAMA,WAAK1C,MAAL,CAAY2C,WAAZ,GAA0B3C,OAAO2C,WAAP,GAAqB3C,OAAO2C,WAA5B,GAA0C,KAApE;AACA,WAAK3C,MAAL,CAAY4C,KAAZ,GAAoB5C,OAAO4C,KAAP,IAAgB,EAApC;AACA,WAAK5C,MAAL,CAAY6C,WAAZ,GAA0B7C,OAAO6C,WAAP,IAAsB,EAAhD;AACA,WAAK7C,MAAL,CAAYiC,IAAZ,GAAmBjC,OAAOiC,IAAP,IAAe,EAAlC;;AAEA;;;AAGA,UAAIa,EAAEC,OAAF,CAAU,KAAK/C,MAAL,CAAYiC,IAAtB,CAAJ,EAAiC;AAC/B,aAAKjC,MAAL,CAAYiC,IAAZ,GAAmB,EAAnB;AACA,aAAKjC,MAAL,CAAYiC,IAAZ,CAAiBC,KAAjB,GAAyB,CAAEC,YAAF,CAAzB;AACD,OAHD,MAGO;AACL,YAAI,CAAC,KAAKnC,MAAL,CAAYiC,IAAZ,CAAiBC,KAAlB,IAA2B,KAAKlC,MAAL,CAAYiC,IAAZ,CAAiBC,KAAjB,CAAuBc,MAAvB,KAAkC,CAAjE,EAAoE;AAClE,eAAKhD,MAAL,CAAYiC,IAAZ,CAAiBC,KAAjB,GAAyB,CAAEC,YAAF,CAAzB;AACD;AACF;;AAED;;;AAGA,UAAI,CAACnC,OAAOmC,YAAZ,EAA0B;AACxB,aAAK,KAAKnC,MAAL,CAAYmC,YAAjB,IAAiC,KAAKnC,MAAL,CAAY4C,KAA7C;AAAoD;AAApD;AACD,OAFD,MAEO;AACL,aAAK5C,MAAL,CAAYmC,YAAZ,GAA2BnC,OAAOmC,YAAlC;AACD;AACF;;AAED;;;;;wBAIoB;AAClB,aAAO,KAAKnC,MAAZ;AACD;;;;;;;kBAjHkBD,W;AA4MpB;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;ACjZA;;;;;;;;;IASqBmB,M;AACjB;;;;;AAKA,wBAAwB;AAAA,QAAVlB,MAAU,QAAVA,MAAU;;AAAA;;AACpB;;;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A,KAFL;AAGLua,iBAAU,OAAAC;AAHL,OAAP;AAKD;;;;EA5DgCxb,M;;AA+DnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;kBA5NqB0Q,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBrB;;;;;;;;;;;IAWqB+K,a;;;AACnB;;;AAGA,+BAAsB;AAAA,QAAT3c,MAAS,QAATA,MAAS;;AAAA;;AAAA,8HACd,EAACA,cAAD,EADc;;AAGpB,UAAK4D,KAAL,GAAa;AACXJ,eAAS,IADE;AAEXoZ,oBAAc,IAFH;AAGXC,uBAAiB;AAHN,KAAb;AAHoB;AAQrB;;AAED;;;;;;;;;;AA2BA;;;;;;;2BAOO;AACL,WAAKjZ,KAAL,CAAWJ,OAAX,GAAqBO,EAAEC,IAAF,CAAO,KAAP,EAAc2Y,cAAcpZ,GAA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ACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;kBAxfqBW,E;;;;;;;;;;;;;;;;AC7BrB;;;;;AAKA,IAAI,CAACqhB,QAAQC,SAAR,CAAkBC,OAAvB,EACEF,QAAQC,SAAR,CAAkBC,OAAlB,GAA4BF,QAAQC,SAAR,CAAkBE,iBAAlB,IACtBH,QAAQC,SAAR,CAAkBG,qBADxB;;AAGF,IAAI,CAACJ,QAAQC,SAAR,CAAkBxN,OAAvB,EACEuN,QAAQC,SAAR,CAAkBxN,OAAlB,GAA4B,UAAU4N,CAAV,EAAa;AACvC,MAAIpa,KAAK,IAAT;;AAEA,MAAI,CAAClB,SAASub,eAAT,CAAyBnG,QAAzB,CAAkClU,EAAlC,CAAL,EAA4C,OAAO,IAAP;AAC5C,KAAG;AACD,QAAIA,GAAGia,OAAH,CAAWG,CAAX,CAAJ,EAAmB,OAAOpa,EAAP;AACnBA,SAAKA,GAAGsa,aAAH,IAAoBta,GAAGiB,UAA5B;AACD,GAHD,QAGSjB,OAAO,IAHhB;AAIA,SAAO,IAAP;AACD,CATD,C;;;;;;;;;;;;;;;;;;;;;;ACVF;;;;IAIqBwE,S;AAC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","file":"codex-editor.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"CodexEditor\"] = factory();\n\telse\n\t\troot[\"CodexEditor\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/codex.js\");\n","module.exports = \"\\n\\n\\n \\n\\n\\n\\n \\n\\n\\n\\n \\n\\n\\n\\n \\n\\n\\n\\n \\n \\n \\n \\n \\n\\n\\n\\n \\n\\n\\n\\n \\n\\n\\n\\n \\n\\n\\n\\n \\n\\n\"","/*\n\tMIT License http://www.opensource.org/licenses/mit-license.php\n\tAuthor Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\nmodule.exports = function(useSourceMap) {\n\tvar list = [];\n\n\t// return the list of modules as css string\n\tlist.toString = function toString() {\n\t\treturn this.map(function (item) {\n\t\t\tvar content = cssWithMappingToString(item, useSourceMap);\n\t\t\tif(item[2]) {\n\t\t\t\treturn \"@media \" + item[2] + \"{\" + content + \"}\";\n\t\t\t} else {\n\t\t\t\treturn content;\n\t\t\t}\n\t\t}).join(\"\");\n\t};\n\n\t// import a list of modules into the list\n\tlist.i = function(modules, mediaQuery) {\n\t\tif(typeof modules === \"string\")\n\t\t\tmodules = [[null, modules, \"\"]];\n\t\tvar alreadyImportedModules = {};\n\t\tfor(var i = 0; i < this.length; i++) {\n\t\t\tvar id = this[i][0];\n\t\t\tif(typeof id === \"number\")\n\t\t\t\talreadyImportedModules[id] = true;\n\t\t}\n\t\tfor(i = 0; i < modules.length; i++) {\n\t\t\tvar item = modules[i];\n\t\t\t// skip already imported module\n\t\t\t// this implementation is not 100% perfect for weird media query combinations\n\t\t\t// when a module is imported multiple times with different media queries.\n\t\t\t// I hope this will never occur (Hey this way we have smaller bundles)\n\t\t\tif(typeof item[0] !== \"number\" || !alreadyImportedModules[item[0]]) {\n\t\t\t\tif(mediaQuery && !item[2]) {\n\t\t\t\t\titem[2] = mediaQuery;\n\t\t\t\t} else if(mediaQuery) {\n\t\t\t\t\titem[2] = \"(\" + item[2] + \") and (\" + mediaQuery + \")\";\n\t\t\t\t}\n\t\t\t\tlist.push(item);\n\t\t\t}\n\t\t}\n\t};\n\treturn list;\n};\n\nfunction cssWithMappingToString(item, useSourceMap) {\n\tvar content = item[1] || '';\n\tvar cssMapping = item[3];\n\tif (!cssMapping) {\n\t\treturn content;\n\t}\n\n\tif (useSourceMap && typeof btoa === 'function') {\n\t\tvar sourceMapping = toComment(cssMapping);\n\t\tvar sourceURLs = cssMapping.sources.map(function (source) {\n\t\t\treturn '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'\n\t\t});\n\n\t\treturn [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n\t}\n\n\treturn [content].join('\\n');\n}\n\n// Adapted from convert-source-map (MIT)\nfunction toComment(sourceMap) {\n\t// eslint-disable-next-line no-undef\n\tvar base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n\tvar data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;\n\n\treturn '/*# ' + data + ' */';\n}\n","(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n define('html-janitor', factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.HTMLJanitor = factory();\n }\n}(this, function () {\n\n /**\n * @param {Object} config.tags Dictionary of allowed tags.\n * @param {boolean} config.keepNestedBlockElements Default false.\n */\n function HTMLJanitor(config) {\n\n var tagDefinitions = config['tags'];\n var tags = Object.keys(tagDefinitions);\n\n var validConfigValues = tags\n .map(function(k) { return typeof tagDefinitions[k]; })\n .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; });\n\n if(!validConfigValues) {\n throw new Error(\"The configuration was invalid\");\n }\n\n this.config = config;\n }\n\n // TODO: not exhaustive?\n var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE'];\n function isBlockElement(node) {\n return blockElementNames.indexOf(node.nodeName) !== -1;\n }\n\n var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE'];\n function isInlineElement(node) {\n return inlineElementNames.indexOf(node.nodeName) !== -1;\n }\n\n HTMLJanitor.prototype.clean = function (html) {\n var sandbox = document.createElement('div');\n sandbox.innerHTML = html;\n\n this._sanitize(sandbox);\n\n return sandbox.innerHTML;\n };\n\n HTMLJanitor.prototype._sanitize = function (parentNode) {\n var treeWalker = createTreeWalker(parentNode);\n var node = treeWalker.firstChild();\n if (!node) { return; }\n\n do {\n // Ignore nodes that have already been sanitized\n if (node._sanitized) {\n continue;\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n // If this text node is just whitespace and the previous or next element\n // sibling is a block element, remove it\n // N.B.: This heuristic could change. Very specific to a bug with\n // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output\n // FIXME: make this an option?\n if (node.data.trim() === ''\n && ((node.previousElementSibling && isBlockElement(node.previousElementSibling))\n || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) {\n parentNode.removeChild(node);\n this._sanitize(parentNode);\n break;\n } else {\n continue;\n }\n }\n\n // Remove all comments\n if (node.nodeType === Node.COMMENT_NODE) {\n parentNode.removeChild(node);\n this._sanitize(parentNode);\n break;\n }\n\n var isInline = isInlineElement(node);\n var containsBlockElement;\n if (isInline) {\n containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement);\n }\n\n // Block elements should not be nested (e.g.
  • ...); if\n // they are, we want to unwrap the inner block element.\n var isNotTopContainer = !! parentNode.parentNode;\n var isNestedBlockElement =\n isBlockElement(parentNode) &&\n isBlockElement(node) &&\n isNotTopContainer;\n\n var nodeName = node.nodeName.toLowerCase();\n\n var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\n var isInvalid = isInline && containsBlockElement;\n\n // Drop tag entirely according to the whitelist *and* if the markup\n // is invalid.\n if (isInvalid || shouldRejectNode(node, allowedAttrs)\n || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n // Do not keep the inner text of SCRIPT/STYLE elements.\n if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n while (node.childNodes.length > 0) {\n parentNode.insertBefore(node.childNodes[0], node);\n }\n }\n parentNode.removeChild(node);\n\n this._sanitize(parentNode);\n break;\n }\n\n // Sanitize attributes\n for (var a = 0; a < node.attributes.length; a += 1) {\n var attr = node.attributes[a];\n\n if (shouldRejectAttr(attr, allowedAttrs, node)) {\n node.removeAttribute(attr.name);\n // Shift the array to continue looping.\n a = a - 1;\n }\n }\n\n // Sanitize children\n this._sanitize(node);\n\n // Mark node as sanitized so it's ignored in future runs\n node._sanitized = true;\n } while ((node = treeWalker.nextSibling()));\n };\n\n function createTreeWalker(node) {\n return document.createTreeWalker(node,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n null, false);\n }\n\n function getAllowedAttrs(config, nodeName, node){\n if (typeof config.tags[nodeName] === 'function') {\n return config.tags[nodeName](node);\n } else {\n return config.tags[nodeName];\n }\n }\n\n function shouldRejectNode(node, allowedAttrs){\n if (typeof allowedAttrs === 'undefined') {\n return true;\n } else if (typeof allowedAttrs === 'boolean') {\n return !allowedAttrs;\n }\n\n return false;\n }\n\n function shouldRejectAttr(attr, allowedAttrs, node){\n var attrName = attr.name.toLowerCase();\n\n if (allowedAttrs === true){\n return false;\n } else if (typeof allowedAttrs[attrName] === 'function'){\n return !allowedAttrs[attrName](attr.value, node);\n } else if (typeof allowedAttrs[attrName] === 'undefined'){\n return true;\n } else if (allowedAttrs[attrName] === false) {\n return true;\n } else if (typeof allowedAttrs[attrName] === 'string') {\n return (allowedAttrs[attrName] !== attr.value);\n }\n\n return false;\n }\n\n return HTMLJanitor;\n\n}));\n","/**\n * Codex Editor\n *\n * Short Description (눈_눈;)\n * @version 2.0.0\n *\n * How to start?\n * Example:\n * new CodexEditor({\n * holderId : 'codex-editor',\n * initialBlock : 'text',\n * placeholder : 'Write your story....',\n * tools: {\n * quote: Quote,\n * anotherTool : AnotherTool\n * },\n * toolsConfig: {\n * quote: {\n * iconClassname : 'quote-icon',\n * displayInToolbox : true,\n * enableLineBreaks : true\n * },\n * anotherTool: {\n * iconClassname : 'tool-icon'\n * }\n * }\n * });\n *\n * - tools is an object: {\n * pluginName: PluginClass,\n * .....\n * }\n * - toolsConfig is an additional configuration that uses Codex Editor API\n * iconClassname - CSS classname of toolbox icon\n * displayInToolbox - if you want to see your Tool in toolbox hided in \"plus\" button, than set \"True\". By default : \"False\"\n * enableLineBreaks - by default enter creates new block that set as initialblock, but if you set this property \"True\", enter will break the lines in current block\n *\n * @author CodeX-Team \n *\n */\n\n/**\n * @typedef {CodexEditor} CodexEditor - editor class\n */\n\n/**\n * @typedef {Object} EditorConfig\n * @property {String} holderId - Element to append Editor\n * @property {Array} data - Blocks list in JSON-format\n * @property {Object} tools - Map for used Tools in format { name : Class, ... }\n * @property {String} initialBlock - This Tool will be added by default\n * @property {String} placeholder - First Block placeholder\n * @property {Object} sanitizer - @todo fill desc\n * @property {Boolean} hideToolbar - @todo fill desc\n * @property {Object} toolsConfig - tools configuration {@link tools#ToolConfig}\n */\n\n/**\n * Dynamically imported utils\n *\n * @typedef {Dom} $ - {@link components/dom.js}\n * @typedef {Util} _ - {@link components/utils.js}\n */\n\n'use strict';\n\n/**\n * Apply polyfills\n */\nimport 'components/polyfills';\n\n/**\n * Require Editor modules places in components/modules dir\n */\n// eslint-disable-next-line\nlet modules = editorModules.map( module => require('./components/modules/' + module ));\n\n/**\n * @class\n *\n * @classdesc CodeX Editor base class\n *\n * @property this.config - all settings\n * @property this.moduleInstances - constructed editor components\n *\n * @type {CodexEditor}\n */\nexport default class CodexEditor {\n /** Editor version */\n static get version() {\n return VERSION;\n }\n\n /**\n * @param {EditorConfig} config - user configuration\n *\n */\n constructor(config) {\n /**\n * Configuration object\n * @type {EditorConfig}\n */\n this.config = {};\n\n /**\n * @typedef {Object} EditorComponents\n * @property {BlockManager} BlockManager\n * @property {Tools} Tools\n * @property {Events} Events\n * @property {UI} UI\n * @property {Toolbar} Toolbar\n * @property {Toolbox} Toolbox\n * @property {BlockSettings} BlockSettings\n * @property {Renderer} Renderer\n * @property {InlineToolbar} InlineToolbar\n */\n this.moduleInstances = {};\n\n Promise.resolve()\n .then(() => {\n this.configuration = config;\n })\n .then(() => this.init())\n .then(() => this.start())\n .then(() => {\n let methods = this.moduleInstances.API.methods;\n\n /**\n * Make API methods available from inside easier\n */\n for (let method in methods) {\n this[method] = methods[method];\n }\n\n delete this.moduleInstances; // todo Is it necessary?\n })\n .then(() => {\n console.log('CodeX Editor is ready!');\n })\n .catch(error => {\n console.log('CodeX Editor does not ready because of %o', error);\n });\n }\n\n /**\n * Setting for configuration\n * @param {EditorConfig} config\n */\n set configuration(config) {\n /**\n * Initlai block type\n * Uses in case when there is no items passed\n * @type {{type: (*), data: {text: null}}}\n */\n let initialBlock = {\n type : config.initialBlock,\n data : {}\n };\n\n this.config.holderId = config.holderId;\n this.config.placeholder = config.placeholder || 'write your story...';\n this.config.sanitizer = config.sanitizer || {\n p: true,\n b: true,\n a: true\n };\n\n this.config.hideToolbar = config.hideToolbar ? config.hideToolbar : false;\n this.config.tools = config.tools || {};\n this.config.toolsConfig = config.toolsConfig || {};\n this.config.data = config.data || {};\n\n /**\n * Initialize items to pass data to the Renderer\n */\n if (_.isEmpty(this.config.data)) {\n this.config.data = {};\n this.config.data.items = [ initialBlock ];\n } else {\n if (!this.config.data.items || this.config.data.items.length === 0) {\n this.config.data.items = [ initialBlock ];\n }\n }\n\n /**\n * If initial Block's Tool was not passed, use the first Tool in config.tools\n */\n if (!config.initialBlock) {\n for (this.config.initialBlock in this.config.tools) break;\n } else {\n this.config.initialBlock = config.initialBlock;\n }\n }\n\n /**\n * Returns private property\n * @returns {EditorConfig}\n */\n get configuration() {\n return this.config;\n }\n\n /**\n * Initializes modules:\n * - make and save instances\n * - configure\n */\n init() {\n /**\n * Make modules instances and save it to the @property this.moduleInstances\n */\n this.constructModules();\n\n /**\n * Modules configuration\n */\n this.configureModules();\n }\n\n /**\n * Make modules instances and save it to the @property this.moduleInstances\n */\n constructModules() {\n modules.forEach( Module => {\n try {\n /**\n * We use class name provided by displayName property\n *\n * On build, Babel will transform all Classes to the Functions so, name will always be 'Function'\n * To prevent this, we use 'babel-plugin-class-display-name' plugin\n * @see https://www.npmjs.com/package/babel-plugin-class-display-name\n */\n this.moduleInstances[Module.displayName] = new Module({\n config : this.configuration\n });\n } catch ( e ) {\n console.log('Module %o skipped because %o', Module, e);\n }\n });\n }\n\n /**\n * Modules instances configuration:\n * - pass other modules to the 'state' property\n * - ...\n */\n configureModules() {\n for(let name in this.moduleInstances) {\n /**\n * Module does not need self-instance\n */\n this.moduleInstances[name].state = this.getModulesDiff( name );\n }\n }\n\n /**\n * Return modules without passed name\n */\n getModulesDiff( name ) {\n let diff = {};\n\n for(let moduleName in this.moduleInstances) {\n /**\n * Skip module with passed name\n */\n if (moduleName === name) {\n continue;\n }\n diff[moduleName] = this.moduleInstances[moduleName];\n }\n\n return diff;\n }\n\n /**\n * Start Editor!\n *\n * Get list of modules that needs to be prepared and return a sequence (Promise)\n * @return {Promise}\n */\n start() {\n let prepareDecorator = module => module.prepare();\n\n return Promise.resolve()\n .then(prepareDecorator(this.moduleInstances.Tools))\n .then(prepareDecorator(this.moduleInstances.UI))\n .then(prepareDecorator(this.moduleInstances.BlockManager))\n .then(() => {\n return this.moduleInstances.Renderer.render(this.config.data.items);\n });\n }\n};\n\n// module.exports = (function (editor) {\n//\n// 'use strict';\n//\n// editor.version = VERSION;\n// editor.scriptPrefix = 'cdx-script-';\n//\n// var init = function () {\n//\n// editor.core = require('./modules/core');\n// editor.tools = require('./modules/tools');\n// editor.ui = require('./modules/ui');\n// editor.transport = require('./modules/transport');\n// editor.renderer = require('./modules/renderer');\n// editor.saver = require('./modules/saver');\n// editor.content = require('./modules/content');\n// editor.toolbar = require('./modules/toolbar/toolbar');\n// editor.callback = require('./modules/callbacks');\n// editor.draw = require('./modules/draw');\n// editor.caret = require('./modules/caret');\n// editor.notifications = require('./modules/notifications');\n// editor.parser = require('./modules/parser');\n// editor.sanitizer = require('./modules/sanitizer');\n// editor.listeners = require('./modules/listeners');\n// editor.destroyer = require('./modules/destroyer');\n// editor.paste = require('./modules/paste');\n//\n// };\n//\n// /**\n// * @public\n// * holds initial settings\n// */\n// editor.settings = {\n// tools : ['text', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n// holderId : 'codex-editor',\n//\n// // Type of block showing on empty editor\n// initialBlockPlugin: 'text'\n// };\n//\n// /**\n// * public\n// *\n// * Static nodes\n// */\n// editor.nodes = {\n// holder : null,\n// wrapper : null,\n// toolbar : null,\n// inlineToolbar : {\n// wrapper : null,\n// buttons : null,\n// actions : null\n// },\n// toolbox : null,\n// notifications : null,\n// plusButton : null,\n// showSettingsButton: null,\n// showTrashButton : null,\n// blockSettings : null,\n// pluginSettings : null,\n// defaultSettings : null,\n// toolbarButtons : {}, // { type : DomEl, ... }\n// redactor : null\n// };\n//\n// /**\n// * @public\n// *\n// * Output state\n// */\n// editor.state = {\n// jsonOutput : [],\n// blocks : [],\n// inputs : []\n// };\n//\n// /**\n// * @public\n// * Editor plugins\n// */\n// editor.tools = {};\n//\n// editor.start = function (userSettings) {\n//\n// init();\n//\n// editor.core.prepare(userSettings)\n//\n// // If all ok, make UI, bind events and parse initial-content\n// .then(editor.ui.prepare)\n// .then(editor.tools.prepare)\n// .then(editor.sanitizer.prepare)\n// .then(editor.paste.prepare)\n// .then(editor.transport.prepare)\n// .then(editor.renderer.makeBlocksFromData)\n// .then(editor.ui.saveInputs)\n// .catch(function (error) {\n//\n// editor.core.log('Initialization failed with error: %o', 'warn', error);\n//\n// });\n//\n// };\n//\n// return editor;\n//\n// })({});\n","/**\n * @abstract\n * @class Module\n * @classdesc All modules inherits from this class.\n *\n * @typedef {Module} Module\n * @property {Object} config - Editor user settings\n * @property {Object} Editor - List of Editor modules\n */\nexport default class Module {\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor({ config }) {\n /**\n * Editor modules list\n * @type {EditorComponents}\n */\n this.Editor = null;\n /**\n * Editor configuration object\n * @type {EditorConfig}\n */\n this.config = {};\n if (new.target === Module) {\n throw new TypeError('Constructors for abstract class Module are not allowed.');\n }\n this.config = config;\n }\n /**\n * Editor modules setter\n *\n * @param Editor\n * @param Editor.modules {@link CodexEditor#moduleInstances}\n * @param Editor.config {@link CodexEditor#configuration}\n */\n set state(Editor) {\n this.Editor = Editor;\n }\n}\n","export default class DeleteTune {\n /**\n * DeleteTune constructor\n *\n * @param {Object} api\n */\n constructor({ api }) {\n /**\n * Styles\n * @type {{wrapper: string}}\n */\n this.CSS = {\n wrapper: 'ass',\n button: 'ce-settings__button',\n buttonDelete: 'ce-settings__button--delete',\n buttonConfirm: 'ce-settings__button--confirm',\n };\n /**\n * Tune nodes\n */\n this.nodes = {\n button: null,\n };\n this.api = api;\n this.resetConfirmation = () => {\n this.setConfirmation(false);\n };\n }\n /**\n * Create \"Delete\" button and add click event listener\n * @returns [Element}\n */\n render() {\n this.nodes.button = $.make('div', [this.CSS.button, this.CSS.buttonDelete], {});\n this.nodes.button.appendChild($.svg('cross', 12, 12));\n this.api.listener.on(this.nodes.button, 'click', (event) => this.handleClick(event), false);\n return this.nodes.button;\n }\n /**\n * Delete block conditions passed\n * @param {MouseEvent} event\n */\n handleClick(event) {\n /**\n * if block is not waiting the confirmation, subscribe on block-settings-closing event to reset\n * otherwise delete block\n */\n if (!this.needConfirmation) {\n this.setConfirmation(true);\n /**\n * Subscribe on event.\n * When toolbar block settings is closed but block deletion is not confirmed,\n * then reset confirmation state\n */\n this.api.events.on('block-settings-closed', this.resetConfirmation);\n }\n else {\n /**\n * Unsubscribe from block-settings closing event\n */\n this.api.events.off('block-settings-closed', this.resetConfirmation);\n this.api.blocks.delete();\n }\n }\n /**\n * change tune state\n */\n setConfirmation(state) {\n this.needConfirmation = state;\n this.nodes.button.classList.add(this.CSS.buttonConfirm);\n }\n}\n","export default class MoveUpTune {\n /**\n * MoveUpTune constructor\n *\n * @param {Object} api\n */\n constructor({ api }) {\n /**\n * Styles\n * @type {{wrapper: string}}\n */\n this.CSS = {\n button: 'ce-settings__button',\n wrapper: 'ce-settings-move-up',\n btnDisabled: 'ce-settings-move-up--disabled',\n };\n this.api = api;\n }\n /**\n * Create \"MoveUp\" button and add click event listener\n * @returns [Element}\n */\n render() {\n const moveUpButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});\n moveUpButton.appendChild($.svg('arrow-up', 14, 14));\n if (this.api.blocks.getCurrentBlockIndex() === 0) {\n moveUpButton.classList.add(this.CSS.btnDisabled);\n }\n else {\n this.api.listener.on(moveUpButton, 'click', (event) => this.handleClick(event), false);\n }\n return moveUpButton;\n }\n /**\n * Move current block up\n * @param {MouseEvent} event\n */\n handleClick(event) {\n const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();\n if (currentBlockIndex === 0) {\n return;\n }\n const currentBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex).html, previousBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex - 1).html;\n /**\n * Here is two cases:\n * - when previous block has negative offset and part of it is visible on window, then we scroll\n * by window's height and add offset which is mathematically difference between two blocks\n *\n * - when previous block is visible and has offset from the window,\n * than we scroll window to the difference between this offsets.\n */\n const currentBlockCoords = currentBlockElement.getBoundingClientRect(), previousBlockCoords = previousBlockElement.getBoundingClientRect();\n let scrollUpOffset;\n if (previousBlockCoords.top > 0) {\n scrollUpOffset = Math.abs(currentBlockCoords.top) - Math.abs(previousBlockCoords.top);\n }\n else {\n scrollUpOffset = window.innerHeight - Math.abs(currentBlockCoords.top) + Math.abs(previousBlockCoords.top);\n }\n window.scrollBy(0, -1 * scrollUpOffset);\n /** Change blocks positions */\n this.api.blocks.swap(currentBlockIndex, currentBlockIndex - 1);\n }\n}\n","/**\n * @class Block\n * @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool\n *\n * @property {Tool} tool — current block tool (Paragraph, for example)\n * @property {Object} CSS — block`s css classes\n *\n */\n\n/** Import default tunes */\nimport MoveUpTune from './block-tunes/block-tune-move-up';\nimport DeleteTune from './block-tunes/block-tune-delete';\n\n/**\n * @classdesc Abstract Block class that contains Block information, Tool name and Tool class instance\n *\n * @property tool - Tool instance\n * @property html - Returns HTML content of plugin\n * @property wrapper - Div element that wraps block content with Tool's content. Has `ce-block` CSS class\n * @property contentNode - Div element that wraps Tool's content. Has `ce-block__content` CSS class\n * @property pluginsContent - HTML content that returns by Tool's render function\n */\nexport default class Block {\n /**\n * @constructor\n * @param {String} toolName - Tool name that passed on initialization\n * @param {Object} toolInstance — passed Tool`s instance that rendered the Block\n * @param {Object} settings - default settings\n * @param {Object} apiMethods - Editor API\n */\n constructor(toolName, toolInstance, settings, apiMethods) {\n this.name = toolName;\n this.tool = toolInstance;\n this.settings = settings;\n this.api = apiMethods;\n this._html = this.compose();\n\n /**\n * @type {IBlockTune[]}\n */\n this.tunes = this.makeTunes();\n }\n\n /**\n * CSS classes for the Block\n * @return {{wrapper: string, content: string}}\n */\n static get CSS() {\n return {\n wrapper: 'ce-block',\n content: 'ce-block__content',\n selected: 'ce-block--selected'\n };\n }\n\n /**\n * Make default Block wrappers and put Tool`s content there\n * @returns {HTMLDivElement}\n */\n compose() {\n this.wrapper = $.make('div', Block.CSS.wrapper);\n this.contentNode = $.make('div', Block.CSS.content);\n this.pluginsContent = this.tool.render();\n\n this.contentNode.appendChild(this.pluginsContent);\n this.wrapper.appendChild(this.contentNode);\n\n return this.wrapper;\n }\n\n /**\n * Calls Tool's method\n *\n * Method checks tool property {MethodName}. Fires method with passes params If it is instance of Function\n *\n * @param {String} methodName\n * @param {Object} params\n */\n call(methodName, params) {\n /**\n * call Tool's method with the instance context\n */\n if (this.tool[methodName] && this.tool[methodName] instanceof Function) {\n this.tool[methodName].call(this.tool, params);\n }\n }\n\n /**\n * Get Block`s HTML\n * @returns {HTMLElement}\n */\n get html() {\n return this._html;\n }\n\n /**\n * Get Block's JSON data\n * @return {Object}\n */\n get data() {\n return this.save();\n }\n\n /**\n * is block mergeable\n * We plugin have merge function then we call it mergable\n * @return {boolean}\n */\n get mergeable() {\n return typeof this.tool.merge === 'function';\n }\n\n /**\n * Call plugins merge method\n * @param {Object} data\n */\n mergeWith(data) {\n return Promise.resolve()\n .then(() => {\n this.tool.merge(data);\n });\n }\n /**\n * Extracts data from Block\n * Groups Tool's save processing time\n * @return {Object}\n */\n save() {\n let extractedBlock = this.tool.save(this.pluginsContent);\n\n /** Measuring execution time*/\n let measuringStart = window.performance.now(),\n measuringEnd;\n\n return Promise.resolve(extractedBlock)\n .then((finishedExtraction) => {\n /** measure promise execution */\n measuringEnd = window.performance.now();\n\n return {\n tool: this.name,\n data: finishedExtraction,\n time : measuringEnd - measuringStart\n };\n })\n .catch(function (error) {\n _.log(`Saving proccess for ${this.tool.name} tool failed due to the ${error}`, 'log', 'red');\n });\n }\n\n /**\n * Uses Tool's validation method to check the correctness of output data\n * Tool's validation method is optional\n *\n * @description Method also can return data if it passed the validation\n *\n * @param {Object} data\n * @returns {Boolean|Object} valid\n */\n validateData(data) {\n let isValid = true;\n\n if (this.tool.validate instanceof Function) {\n isValid = this.tool.validate(data);\n }\n\n if (!isValid) {\n return false;\n }\n\n return data;\n }\n\n /**\n * Make an array with default settings\n * Each block has default tune instance that have states\n * @return {IBlockTune[]}\n */\n makeTunes() {\n let tunesList = [MoveUpTune, DeleteTune];\n\n // Pluck tunes list and return tune instances with passed Editor API and settings\n return tunesList.map( (tune) => {\n return new tune({\n api: this.api,\n settings: this.settings,\n });\n });\n }\n\n /**\n * Enumerates initialized tunes and returns fragment that can be appended to the toolbars area\n * @return {DocumentFragment}\n */\n renderTunes() {\n let tunesElement = document.createDocumentFragment();\n\n this.tunes.forEach( tune => {\n $.append(tunesElement, tune.render());\n });\n\n return tunesElement;\n }\n\n /**\n * Check block for emptiness\n * @return {Boolean}\n */\n get isEmpty() {\n /**\n * Allow Tool to represent decorative contentless blocks: for example \"* * *\"-tool\n * That Tools are not empty\n */\n if (this.tool.contentless) {\n return false;\n }\n\n let emptyText = $.isEmpty(this.pluginsContent),\n emptyMedia = !this.hasMedia;\n\n return emptyText && emptyMedia;\n }\n\n /**\n * Check if block has a media content such as images, iframes and other\n * @return {Boolean}\n */\n get hasMedia() {\n /**\n * This tags represents media-content\n * @type {string[]}\n */\n const mediaTags = [\n 'img',\n 'iframe',\n 'video',\n 'audio',\n 'source',\n 'input',\n 'textarea',\n 'twitterwidget'\n ];\n\n return !!this._html.querySelector(mediaTags.join(','));\n }\n\n /**\n * Set selected state\n * @param {Boolean} state - 'true' to select, 'false' to remove selection\n */\n set selected(state) {\n /**\n * We don't need to mark Block as Selected when it is not empty\n */\n if (state === true && !this.isEmpty) {\n this._html.classList.add(Block.CSS.selected);\n } else {\n this._html.classList.remove(Block.CSS.selected);\n }\n }\n}\n","/**\n * DOM manipulations helper\n */\nexport default class Dom {\n /**\n * Check if passed tag has no closed tag\n * @param {Element} tag\n * @return {Boolean}\n */\n static isSingleTag(tag) {\n return tag.tagName && ['AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'].includes(tag.tagName);\n };\n\n\n /**\n * Helper for making Elements with classname and attributes\n *\n * @param {string} tagName - new Element tag name\n * @param {array|string} classNames - list or name of CSS classname(s)\n * @param {Object} attributes - any attributes\n * @return {Element}\n */\n static make(tagName, classNames = null, attributes = {}) {\n let el = document.createElement(tagName);\n\n if ( Array.isArray(classNames) ) {\n el.classList.add(...classNames);\n } else if( classNames ) {\n el.classList.add(classNames);\n }\n\n for (let attrName in attributes) {\n el[attrName] = attributes[attrName];\n }\n\n return el;\n }\n\n /**\n * Creates Text Node with the passed content\n * @param {String} content - text content\n * @return {Text}\n */\n static text(content) {\n return document.createTextNode(content);\n }\n\n /**\n * Creates SVG icon linked to the sprite\n * @param {string} name - name (id) of icon from sprite\n * @param {number} width\n * @param {number} height\n * @return {SVGElement}\n */\n static svg(name, width = 14, height = 14) {\n let icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n\n icon.classList.add('icon', 'icon--' + name);\n icon.setAttribute('width', width + 'px');\n icon.setAttribute('height', height + 'px');\n icon.innerHTML = ``;\n\n return icon;\n }\n\n /**\n * Append one or several elements to the parent\n *\n * @param {Element} parent - where to append\n * @param {Element|Element[]} - element ore elements list\n */\n static append(parent, elements) {\n if ( Array.isArray(elements) ) {\n elements.forEach( el => parent.appendChild(el) );\n } else {\n parent.appendChild(elements);\n }\n }\n\n /**\n * Swap two elements in parent\n * @param {HTMLElement} el1 - from\n * @param {HTMLElement} el2 - to\n */\n static swap(el1, el2) {\n // create marker element and insert it where el1 is\n const temp = document.createElement('div'),\n parent = el1.parentNode;\n\n parent.insertBefore(temp, el1);\n\n // move el1 to right before el2\n parent.insertBefore(el1, el2);\n\n // move el2 to right before where el1 used to be\n parent.insertBefore(el2, temp);\n\n // remove temporary marker node\n parent.removeChild(temp);\n }\n\n /**\n * Selector Decorator\n *\n * Returns first match\n *\n * @param {Element} el - element we searching inside. Default - DOM Document\n * @param {String} selector - searching string\n *\n * @returns {Element}\n */\n static find(el = document, selector) {\n return el.querySelector(selector);\n }\n\n /**\n * Selector Decorator.\n *\n * Returns all matches\n *\n * @param {Element} el - element we searching inside. Default - DOM Document\n * @param {String} selector - searching string\n * @returns {NodeList}\n */\n static findAll(el = document, selector) {\n return el.querySelectorAll(selector);\n }\n\n /**\n * Search for deepest node which is Leaf.\n * Leaf is the vertex that doesn't have any child nodes\n *\n * @description Method recursively goes throw the all Node until it finds the Leaf\n *\n * @param {Node} node - root Node. From this vertex we start Deep-first search {@link https://en.wikipedia.org/wiki/Depth-first_search}\n * @param {Boolean} atLast - find last text node\n * @return {Node} - it can be text Node or Element Node, so that caret will able to work with it\n */\n static getDeepestNode(node, atLast = false) {\n /**\n * Current function have two directions:\n * - starts from first child and every time gets first or nextSibling in special cases\n * - starts from last child and gets last or previousSibling\n * @type {string}\n */\n let child = atLast ? 'lastChild' : 'firstChild',\n sibling = atLast ? 'previousSibling' : 'nextSibling';\n\n if (node && node.nodeType === Node.ELEMENT_NODE && node[child]) {\n let nodeChild = node[child];\n\n /**\n * special case when child is single tag that can't contain any content\n */\n if (Dom.isSingleTag(nodeChild)) {\n /**\n * 1) We need to check the next sibling. If it is Node Element then continue searching for deepest\n * from sibling\n *\n * 2) If single tag's next sibling is null, then go back to parent and check his sibling\n * In case of Node Element continue searching\n *\n * 3) If none of conditions above happened return parent Node Element\n */\n if (nodeChild[sibling]) {\n nodeChild = nodeChild[sibling];\n } else if (nodeChild.parentNode[sibling]) {\n nodeChild = nodeChild.parentNode[sibling];\n } else {\n return nodeChild.parentNode;\n }\n }\n\n return this.getDeepestNode(nodeChild, atLast);\n }\n\n return node;\n }\n\n /**\n * Check if object is DOM node\n *\n * @param {Object} node\n * @returns {boolean}\n */\n static isElement(node) {\n return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE;\n }\n\n /**\n * Checks target if it is native input\n * @param {Element|String} target - HTML element or string\n * @return {Boolean}\n */\n static isNativeInput(target) {\n let nativeInputs = [\n 'INPUT',\n 'TEXTAREA'\n ];\n\n return target ? nativeInputs.includes(target.tagName) : false;\n }\n\n /**\n * Checks node if it is empty\n *\n * @description Method checks simple Node without any childs for emptiness\n * If you have Node with 2 or more children id depth, you better use {@link Dom#isEmpty} method\n *\n * @param {Node} node\n * @return {Boolean} true if it is empty\n */\n static isNodeEmpty(node) {\n let nodeText;\n\n if ( this.isElement(node) && this.isNativeInput(node) ) {\n nodeText = node.value;\n } else {\n nodeText = node.textContent.replace('\\u200B', '');\n }\n\n return nodeText.trim().length === 0;\n }\n\n /**\n * checks node if it is doesn't have any child nodes\n * @param {Node} node\n * @return {boolean}\n */\n static isLeaf(node) {\n if (!node) {\n return false;\n }\n\n return node.childNodes.length === 0;\n }\n\n /**\n * breadth-first search (BFS)\n * {@link https://en.wikipedia.org/wiki/Breadth-first_search}\n *\n * @description Pushes to stack all DOM leafs and checks for emptiness\n *\n * @param {Node} node\n * @return {boolean}\n */\n static isEmpty(node) {\n let treeWalker = [],\n leafs = [];\n\n if (!node) {\n return true;\n }\n\n if (!node.childNodes.length) {\n return this.isNodeEmpty(node);\n }\n\n treeWalker.push(node.firstChild);\n\n while ( treeWalker.length > 0 ) {\n node = treeWalker.shift();\n\n if (!node) continue;\n\n if ( this.isLeaf(node) ) {\n leafs.push(node);\n } else {\n treeWalker.push(node.firstChild);\n }\n\n while ( node && node.nextSibling ) {\n node = node.nextSibling;\n\n if (!node) continue;\n\n treeWalker.push(node);\n }\n\n /**\n * If one of childs is not empty, checked Node is not empty too\n */\n if (node && !this.isNodeEmpty(node)) {\n return false;\n }\n }\n\n return leafs.every( leaf => this.isNodeEmpty(leaf) );\n }\n};\n","/**\n * Bold Tool\n *\n * Inline Toolbar Tool\n *\n * Makes selected text bolder\n */\nexport default class BoldInlineTool {\n constructor(api) {\n /**\n * Native Document's command that uses for Bold\n */\n this.commandName = 'bold';\n /**\n * Styles\n */\n this.CSS = {\n button: 'ce-inline-tool',\n buttonActive: 'ce-inline-tool--active',\n buttonModifier: 'ce-inline-tool--bold',\n };\n /**\n * Elements\n */\n this.nodes = {\n button: null,\n };\n console.log('Bold Inline Tool is ready');\n }\n /**\n * Create button for Inline Toolbar\n */\n render() {\n this.nodes.button = document.createElement('button');\n this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);\n this.nodes.button.appendChild($.svg('bold', 13, 15));\n return this.nodes.button;\n }\n /**\n * Wrap range with tag\n * @param {Range} range\n */\n surround(range) {\n document.execCommand(this.commandName);\n }\n /**\n * Check selection and set activated state to button if there are tag\n * @param {Selection} selection\n */\n checkState(selection) {\n const isActive = document.queryCommandState(this.commandName);\n this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);\n return isActive;\n }\n}\n","/**\n * Italic Tool\n *\n * Inline Toolbar Tool\n *\n * Style selected text with italic\n */\nexport default class ItalicInlineTool {\n constructor(api) {\n /**\n * Native Document's command that uses for Italic\n */\n this.commandName = 'italic';\n /**\n * Styles\n */\n this.CSS = {\n button: 'ce-inline-tool',\n buttonActive: 'ce-inline-tool--active',\n buttonModifier: 'ce-inline-tool--italic',\n };\n /**\n * Elements\n */\n this.nodes = {\n button: null,\n };\n console.log('Italic Inline Tool is ready');\n }\n /**\n * Create button for Inline Toolbar\n */\n render() {\n this.nodes.button = document.createElement('button');\n this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);\n this.nodes.button.appendChild($.svg('italic', 6, 15));\n return this.nodes.button;\n }\n /**\n * Wrap range with tag\n * @param {Range} range\n */\n surround(range) {\n document.execCommand(this.commandName);\n }\n /**\n * Check selection and set activated state to button if there are tag\n * @param {Selection} selection\n */\n checkState(selection) {\n const isActive = document.queryCommandState(this.commandName);\n this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);\n return isActive;\n }\n}\n","import Selection from '../selection';\n/**\n * Link Tool\n *\n * Inline Toolbar Tool\n *\n * Wrap selected text with tag\n */\nexport default class LinkInlineTool {\n /**\n * @param {object} api - CodeX Editor API\n * @param {object} api.toolbar - Inline Toolbar API\n */\n constructor(api) {\n /**\n * Native Document's commands for link/unlink\n */\n this.commandLink = 'createLink';\n this.commandUnlink = 'unlink';\n /**\n * Enter key code\n */\n this.ENTER_KEY = 13;\n /**\n * Styles\n */\n this.CSS = {\n button: 'ce-inline-tool',\n buttonActive: 'ce-inline-tool--active',\n buttonModifier: 'ce-inline-tool--link',\n buttonUnlink: 'ce-inline-tool--unlink',\n input: 'ce-inline-tool-input',\n inputShowed: 'ce-inline-tool-input--showed',\n };\n /**\n * Elements\n */\n this.nodes = {\n button: null,\n input: null,\n };\n /**\n * Input opening state\n */\n this.inputOpened = false;\n this.inlineToolbar = api.toolbar;\n this.selection = new Selection();\n }\n /**\n * Create button for Inline Toolbar\n */\n render() {\n this.nodes.button = document.createElement('button');\n this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);\n this.nodes.button.appendChild($.svg('link', 15, 14));\n this.nodes.button.appendChild($.svg('unlink', 16, 18));\n return this.nodes.button;\n }\n /**\n * Input for the link\n */\n renderActions() {\n this.nodes.input = document.createElement('input');\n this.nodes.input.placeholder = 'Add a link';\n this.nodes.input.classList.add(this.CSS.input);\n this.nodes.input.addEventListener('keydown', (event) => {\n if (event.keyCode === this.ENTER_KEY) {\n this.enterPressed(event);\n }\n });\n return this.nodes.input;\n }\n /**\n * Handle clicks on the Inline Toolbar icon\n * @param {Range} range\n */\n surround(range) {\n /**\n * Range will be null when user makes second click on the 'link icon' to close opened input\n */\n if (range) {\n /**\n * Save selection before change focus to the input\n */\n this.selection.save();\n const parentAnchor = this.selection.findParentTag('A');\n /**\n * Unlink icon pressed\n */\n if (parentAnchor) {\n this.selection.expandToTag(parentAnchor);\n this.unlink();\n this.closeActions();\n this.checkState();\n this.inlineToolbar.close();\n return;\n }\n }\n this.toggleActions();\n }\n /**\n * Check selection and set activated state to button if there are tag\n * @param {Selection} selection\n */\n checkState(selection) {\n const anchorTag = this.selection.findParentTag('A');\n if (anchorTag) {\n this.nodes.button.classList.add(this.CSS.buttonUnlink);\n this.nodes.button.classList.add(this.CSS.buttonActive);\n this.openActions();\n /**\n * Fill input value with link href\n */\n const hrefAttr = anchorTag.getAttribute('href');\n this.nodes.input.value = hrefAttr !== 'null' ? hrefAttr : '';\n this.selection.save();\n }\n else {\n this.nodes.button.classList.remove(this.CSS.buttonUnlink);\n this.nodes.button.classList.remove(this.CSS.buttonActive);\n }\n return !!anchorTag;\n }\n /**\n * Function called with Inline Toolbar closing\n */\n clear() {\n this.closeActions();\n }\n toggleActions() {\n if (!this.inputOpened) {\n this.openActions(true);\n }\n else {\n this.closeActions(false);\n }\n }\n /**\n * @param {boolean} needFocus - on link creation we need to focus input. On editing - nope.\n */\n openActions(needFocus = false) {\n this.nodes.input.classList.add(this.CSS.inputShowed);\n if (needFocus) {\n this.nodes.input.focus();\n }\n this.inputOpened = true;\n }\n /**\n * Close input\n * @param {boolean} clearSavedSelection — we don't need to clear saved selection\n * on toggle-clicks on the icon of opened Toolbar\n */\n closeActions(clearSavedSelection = true) {\n this.nodes.input.classList.remove(this.CSS.inputShowed);\n this.nodes.input.value = '';\n if (clearSavedSelection) {\n this.selection.clearSaved();\n }\n this.inputOpened = false;\n }\n /**\n * Enter pressed on input\n * @param {KeyboardEvent} event\n */\n enterPressed(event) {\n let value = this.nodes.input.value || '';\n if (!value.trim()) {\n this.selection.restore();\n this.unlink();\n event.preventDefault();\n this.closeActions();\n }\n if (!this.validateURL(value)) {\n /**\n * @todo show notification 'Incorrect Link'\n */\n _.log('Incorrect Link pasted', 'warn', value);\n return;\n }\n value = this.prepareLink(value);\n this.selection.restore();\n this.insertLink(value);\n /**\n * Preventing events that will be able to happen\n */\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n this.closeActions();\n this.inlineToolbar.close();\n this.checkState();\n }\n /**\n * Detects if passed string is URL\n * @param {string} str\n * @return {Boolean}\n */\n validateURL(str) {\n /**\n * Don't allow spaces\n */\n return !/\\s/.test(str);\n }\n /**\n * Process link before injection\n * - sanitize\n * - add protocol for links like 'google.com'\n * @param {string} link - raw user input\n */\n prepareLink(link) {\n link = link.trim();\n link = this.addProtocol(link);\n return link;\n }\n /**\n * Add 'http' protocol to the links like 'vc.ru', 'google.com'\n * @param {String} link\n */\n addProtocol(link) {\n /**\n * If protocol already exists, do nothing\n */\n if (/^(\\w+):\\/\\//.test(link)) {\n return link;\n }\n /**\n * We need to add missed HTTP protocol to the link, but skip 2 cases:\n * 1) Internal links like \"/general\"\n * 2) Anchors looks like \"#results\"\n * 3) Protocol-relative URLs like \"//google.com\"\n */\n const isInternal = /^\\/[^\\/\\s]/.test(link), isAnchor = link.substring(0, 1) === '#', isProtocolRelative = /^\\/\\/[^\\/\\s]/.test(link);\n if (!isInternal && !isAnchor && !isProtocolRelative) {\n link = 'http://' + link;\n }\n return link;\n }\n /**\n * Inserts tag with \"href\"\n * @param {string} link - \"href\" value\n */\n insertLink(link) {\n /**\n * Edit all link, not selected part\n */\n const anchorTag = this.selection.findParentTag('A');\n if (anchorTag) {\n this.selection.expandToTag(anchorTag);\n }\n document.execCommand(this.commandLink, false, link);\n }\n /**\n * Removes tag\n */\n unlink() {\n document.execCommand(this.commandUnlink);\n }\n}\n","var map = {\n\t\"./api-blocks.ts\": \"./src/components/modules/api-blocks.ts\",\n\t\"./api-events.ts\": \"./src/components/modules/api-events.ts\",\n\t\"./api-listener.ts\": \"./src/components/modules/api-listener.ts\",\n\t\"./api-sanitizer.ts\": \"./src/components/modules/api-sanitizer.ts\",\n\t\"./api-saver.ts\": \"./src/components/modules/api-saver.ts\",\n\t\"./api-selection.ts\": \"./src/components/modules/api-selection.ts\",\n\t\"./api-toolbar.ts\": \"./src/components/modules/api-toolbar.ts\",\n\t\"./api.ts\": \"./src/components/modules/api.ts\",\n\t\"./block-events.ts\": \"./src/components/modules/block-events.ts\",\n\t\"./blockManager.js\": \"./src/components/modules/blockManager.js\",\n\t\"./caret.js\": \"./src/components/modules/caret.js\",\n\t\"./events.js\": \"./src/components/modules/events.js\",\n\t\"./listeners.js\": \"./src/components/modules/listeners.js\",\n\t\"./renderer.js\": \"./src/components/modules/renderer.js\",\n\t\"./sanitizer.js\": \"./src/components/modules/sanitizer.js\",\n\t\"./saver.js\": \"./src/components/modules/saver.js\",\n\t\"./toolbar-blockSettings.js\": \"./src/components/modules/toolbar-blockSettings.js\",\n\t\"./toolbar-inline.ts\": \"./src/components/modules/toolbar-inline.ts\",\n\t\"./toolbar-toolbox.js\": \"./src/components/modules/toolbar-toolbox.js\",\n\t\"./toolbar.js\": \"./src/components/modules/toolbar.js\",\n\t\"./tools.js\": \"./src/components/modules/tools.js\",\n\t\"./ui.js\": \"./src/components/modules/ui.js\"\n};\n\n\nfunction webpackContext(req) {\n\tvar id = webpackContextResolve(req);\n\treturn __webpack_require__(id);\n}\nfunction webpackContextResolve(req) {\n\tvar id = map[req];\n\tif(!(id + 1)) { // check for number or string\n\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\treturn id;\n}\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = \"./src/components/modules sync [^_](api-blocks.ts|api-events.ts|api-listener.ts|api-sanitizer.ts|api-saver.ts|api-selection.ts|api-toolbar.ts|api.ts|block-events.ts|blockManager.js|caret.js|events.js|listeners.js|renderer.js|sanitizer.js|saver.js|toolbar-blockSettings.js|toolbar-inline.ts|toolbar-toolbox.js|toolbar.js|tools.js|ui.js)$\";","/**\n * @class BlocksAPI\n * provides with methods working with Block\n */\nexport default class BlocksAPI extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorsConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * Available methods\n * @return {IBlocksAPI}\n */\n get methods() {\n return {\n clear: () => this.clear(),\n render: (data) => this.render(data),\n delete: () => this.delete(),\n swap: (fromIndex, toIndex) => this.swap(fromIndex, toIndex),\n getBlockByIndex: (index) => this.getBlockByIndex(index),\n getCurrentBlockIndex: () => this.getCurrentBlockIndex(),\n };\n }\n /**\n * Returns current block index\n * @return {number}\n */\n getCurrentBlockIndex() {\n return this.Editor.BlockManager.currentBlockIndex;\n }\n /**\n * Returns Current Block\n * @param {Number} index\n *\n * @return {Object}\n */\n getBlockByIndex(index) {\n return this.Editor.BlockManager.getBlockByIndex(index);\n }\n /**\n * Call Block Manager method that swap Blocks\n * @param {number} fromIndex - position of first Block\n * @param {number} toIndex - position of second Block\n */\n swap(fromIndex, toIndex) {\n this.Editor.BlockManager.swap(fromIndex, toIndex);\n /**\n * Move toolbar\n * DO not close the settings\n */\n this.Editor.Toolbar.move(false);\n }\n /**\n * Deletes Block\n * @param blockIndex\n */\n delete(blockIndex) {\n this.Editor.BlockManager.removeBlock(blockIndex);\n /**\n * in case of last block deletion\n * Insert new initial empty block\n */\n if (this.Editor.BlockManager.blocks.length === 0) {\n this.Editor.BlockManager.insert();\n }\n /**\n * In case of deletion first block we need to set caret to the current Block\n */\n if (this.Editor.BlockManager.currentBlockIndex === 0) {\n this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock);\n }\n else {\n if (this.Editor.Caret.navigatePrevious(true)) {\n this.Editor.Toolbar.close();\n }\n }\n }\n /**\n * Clear Editor's area\n */\n clear() {\n this.Editor.BlockManager.clear(true);\n }\n /**\n * Fills Editor with Blocks data\n * @param {IInputOutputData} data — Saved Editor data\n */\n render(data) {\n this.Editor.BlockManager.clear();\n this.Editor.Renderer.render(data.items);\n }\n}\n","/**\n * @class EventsAPI\n * provides with methods working with Toolbar\n */\nexport default class EventsAPI extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorsConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * Available methods\n * @return {IEventsAPI}\n */\n get methods() {\n return {\n emit: (eventName, data) => this.emit(eventName, data),\n off: (eventName, callback) => this.off(eventName, callback),\n on: (eventName, callback) => this.on(eventName, callback),\n };\n }\n /**\n * Subscribe on Events\n * @param {String} eventName\n * @param {Function} callback\n */\n on(eventName, callback) {\n this.Editor.Events.on(eventName, callback);\n }\n /**\n * Emit event with data\n * @param {String} eventName\n * @param {Object} data\n */\n emit(eventName, data) {\n this.Editor.Events.emit(eventName, data);\n }\n /**\n * Unsubscribe from Event\n * @param {String} eventName\n * @param {Function} callback\n */\n off(eventName, callback) {\n this.Editor.Events.off(eventName, callback);\n }\n}\n","/**\n * @class API\n * Provides with methods working with DOM Listener\n */\nexport default class ListenerAPI extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorsConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * Available methods\n * @return {IToolbarAPI}\n */\n get methods() {\n return {\n on: (element, eventType, handler, useCapture) => this.on(element, eventType, handler, useCapture),\n off: (element, eventType, handler) => this.off(element, eventType, handler),\n };\n }\n /**\n * adds DOM event listener\n *\n * @param {HTMLElement} element\n * @param {string} eventType\n * @param {() => void} handler\n * @param {boolean} useCapture\n */\n on(element, eventType, handler, useCapture) {\n this.Editor.Listeners.on(element, eventType, handler, useCapture);\n }\n /**\n * Removes DOM listener from element\n *\n * @param element\n * @param eventType\n * @param handler\n */\n off(element, eventType, handler) {\n this.Editor.Listeners.off(element, eventType, handler);\n }\n}\n","/**\n * @class API\n * Provides CodeX Editor Sanitizer that allows developers to clean their HTML\n */\nexport default class SanitizerAPI extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorsConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * Available methods\n * @return {ISanitizerAPI}\n */\n get methods() {\n return {\n clean: (taintString, config) => this.clean(taintString, config),\n };\n }\n clean(taintString, config) {\n return this.Editor.Sanitizer.clean(taintString, config);\n }\n}\n","/**\n * @class SaverAPI\n * provides with methods to save data\n */\nexport default class SaverAPI extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorsConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * Available methods\n * @return {ISaverAPI}\n */\n get methods() {\n return {\n save: () => this.save(),\n };\n }\n /**\n * Return Editor's data\n */\n save() {\n return this.Editor.Saver.save();\n }\n}\n","import Selection from '../selection';\n/**\n * @class API\n * Provides with methods working with Selection\n */\nexport default class SelectionAPI extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorsConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * Available methods\n * @return {ISelectionAPI}\n */\n get methods() {\n return {\n findParentTag: (tagName, className) => this.findParentTag(tagName, className),\n expandToTag: (node) => this.expandToTag(node),\n };\n }\n /**\n * Looks ahead from selection and find passed tag with class name\n * @param {string} tagName - tag to find\n * @param {string} className - tag's class name\n * @return {HTMLElement|null}\n */\n findParentTag(tagName, className) {\n return new Selection().findParentTag(tagName, className);\n }\n /**\n * Expand selection to passed tag\n * @param {HTMLElement} node - tag that should contain selection\n */\n expandToTag(node) {\n new Selection().expandToTag(node);\n }\n}\n","/**\n * @class ToolbarsAPI\n * provides with methods working with Toolbar\n */\nexport default class ToolbarAPI extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorsConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * Available methods\n * @return {IToolbarAPI}\n */\n get methods() {\n return {\n close: () => this.close(),\n open: () => this.open(),\n };\n }\n /**\n * Open toolbar\n */\n open() {\n this.Editor.Toolbar.open();\n }\n /**\n * Close toolbar and all included elements\n */\n close() {\n this.Editor.Toolbar.close();\n }\n}\n","/**\n * @class API\n */\nexport default class API extends Module {\n /**\n * Save Editor config. API provides passed configuration to the Blocks\n * @param {EditorConfig} config\n */\n constructor({ config }) {\n super({ config });\n }\n get methods() {\n return {\n blocks: this.Editor.BlocksAPI.methods,\n caret: {},\n events: this.Editor.EventsAPI.methods,\n sanitizer: this.Editor.SanitizerAPI.methods,\n saver: this.Editor.SaverAPI.methods,\n selection: this.Editor.SelectionAPI.methods,\n listener: this.Editor.ListenerAPI.methods,\n toolbar: this.Editor.ToolbarAPI.methods,\n };\n }\n}\n","export default class BlockEvents extends Module {\n /**\n * @constructor\n */\n constructor({ config }) {\n super({ config });\n }\n /**\n * All keydowns on Block\n * @param {KeyboardEvent} event - keydown\n */\n keydown(event) {\n switch (event.keyCode) {\n case _.keyCodes.BACKSPACE:\n this.backspace(event);\n break;\n case _.keyCodes.ENTER:\n this.enter(event);\n break;\n case _.keyCodes.DOWN:\n case _.keyCodes.RIGHT:\n this.arrowRightAndDownPressed();\n break;\n case _.keyCodes.UP:\n case _.keyCodes.LEFT:\n this.arrowLeftAndUpPressed();\n break;\n default:\n break;\n }\n }\n /**\n * Key up on Block:\n * - shows Inline Toolbar if something selected\n */\n keyup(event) {\n this.Editor.InlineToolbar.handleShowingEvent(event);\n }\n /**\n * Mouse up on Block:\n * - shows Inline Toolbar if something selected\n */\n mouseUp(event) {\n this.Editor.InlineToolbar.handleShowingEvent(event);\n }\n /**\n * ENTER pressed on block\n * @param {KeyboardEvent} event - keydown\n */\n enter(event) {\n const currentBlock = this.Editor.BlockManager.currentBlock, toolsConfig = this.config.toolsConfig[currentBlock.name];\n /**\n * Don't handle Enter keydowns when Tool sets enableLineBreaks to true.\n * Uses for Tools like where line breaks should be handled by default behaviour.\n */\n if (toolsConfig && toolsConfig[this.Editor.Tools.apiSettings.IS_ENABLED_LINE_BREAKS]) {\n return;\n }\n /**\n * Allow to create linebreaks by Shift+Enter\n */\n if (event.shiftKey) {\n return;\n }\n /**\n * Split the Current Block into two blocks\n */\n this.Editor.BlockManager.split();\n /**\n * Renew local current node after split\n */\n const newCurrent = this.Editor.BlockManager.currentBlock;\n this.Editor.Toolbar.move();\n this.Editor.Toolbar.open();\n if (this.Editor.Tools.isInitial(newCurrent.tool) && newCurrent.isEmpty) {\n this.Editor.Toolbar.plusButton.show();\n }\n event.preventDefault();\n }\n /**\n * Handle backspace keydown on Block\n * @param {KeyboardEvent} event - keydown\n */\n backspace(event) {\n const BM = this.Editor.BlockManager;\n const isFirstBlock = BM.currentBlockIndex === 0, canMergeBlocks = this.Editor.Caret.isAtStart && !isFirstBlock;\n if (!canMergeBlocks) {\n return;\n }\n // preventing browser default behaviour\n event.preventDefault();\n const targetBlock = BM.getBlockByIndex(BM.currentBlockIndex - 1), blockToMerge = BM.currentBlock;\n /**\n * Blocks that can be merged:\n * 1) with the same Name\n * 2) Tool has 'merge' method\n *\n * other case will handle as usual ARROW LEFT behaviour\n */\n if (blockToMerge.name !== targetBlock.name || !targetBlock.mergeable) {\n if (this.Editor.Caret.navigatePrevious()) {\n this.Editor.Toolbar.close();\n }\n }\n const setCaretToTheEnd = !targetBlock.isEmpty;\n BM.mergeBlocks(targetBlock, blockToMerge)\n .then(() => {\n // @todo figure out without timeout\n window.setTimeout(() => {\n // set caret to the block without offset at the end\n this.Editor.Caret.setToBlock(BM.currentBlock, 0, setCaretToTheEnd);\n this.Editor.Toolbar.close();\n }, 10);\n });\n }\n /**\n * Handle right and down keyboard keys\n */\n arrowRightAndDownPressed() {\n this.Editor.Caret.navigateNext();\n this.Editor.Toolbar.close();\n }\n /**\n * Handle left and up keyboard keys\n */\n arrowLeftAndUpPressed() {\n this.Editor.Caret.navigatePrevious();\n this.Editor.Toolbar.close();\n }\n}\n","/**\n * @class BlockManager\n * @classdesc Manage editor`s blocks storage and appearance\n *\n * @module BlockManager\n *\n * @version 2.0.0\n */\n\nimport Block from '../block';\n\n/**\n * @typedef {BlockManager} BlockManager\n * @property {Number} currentBlockIndex - Index of current working block\n * @property {Proxy} _blocks - Proxy for Blocks instance {@link Blocks}\n */\nexport default class BlockManager extends Module {\n /**\n * @constructor\n * @param {EditorConfig} config\n */\n constructor({config}) {\n super({config});\n\n /**\n * Proxy for Blocks instance {@link Blocks}\n *\n * @type {Proxy}\n * @private\n */\n this._blocks = null;\n\n /**\n * Index of current working block\n *\n * @type {number}\n * @private\n */\n this.currentBlockIndex = -1;\n }\n\n /**\n * Should be called after Editor.UI preparation\n * Define this._blocks property\n *\n * @returns {Promise}\n */\n prepare() {\n return new Promise(resolve => {\n let blocks = new Blocks(this.Editor.UI.nodes.redactor);\n\n /**\n * We need to use Proxy to overload set/get [] operator.\n * So we can use array-like syntax to access blocks\n *\n * @example\n * this._blocks[0] = new Block(...);\n *\n * block = this._blocks[0];\n *\n * @todo proxy the enumerate method\n *\n * @type {Proxy}\n * @private\n */\n this._blocks = new Proxy(blocks, {\n set: Blocks.set,\n get: Blocks.get\n });\n\n resolve();\n });\n }\n\n /**\n * Creates Block instance by tool name\n *\n * @param {String} toolName - tools passed in editor config {@link EditorConfig#tools}\n * @param {Object} data - constructor params\n * @param {Object} settings - block settings\n *\n * @return {Block}\n */\n composeBlock(toolName, data, settings) {\n let toolInstance = this.Editor.Tools.construct(toolName, data),\n block = new Block(toolName, toolInstance, settings, this.Editor.API.methods);\n\n this.bindEvents(block);\n /**\n * Apply callback before inserting html\n */\n block.call('appendCallback', {});\n\n return block;\n }\n\n /**\n * Bind Events\n * @param {Object} block\n */\n bindEvents(block) {\n this.Editor.Listeners.on(block.pluginsContent, 'keydown', (event) => this.Editor.BlockEvents.keydown(event));\n this.Editor.Listeners.on(block.pluginsContent, 'mouseup', (event) => this.Editor.BlockEvents.mouseUp(event));\n this.Editor.Listeners.on(block.pluginsContent, 'keyup', (event) => this.Editor.BlockEvents.keyup(event));\n }\n\n /**\n * Insert new block into _blocks\n *\n * @param {String} toolName — plugin name, by default method inserts initial block type\n * @param {Object} data — plugin data\n * @param {Object} settings - default settings\n *\n * @return {Block}\n */\n insert(toolName = this.config.initialBlock, data = {}, settings = {}) {\n let block = this.composeBlock(toolName, data, settings);\n\n this._blocks[++this.currentBlockIndex] = block;\n this.Editor.Caret.setToBlock(block);\n\n return block;\n }\n\n /**\n * Merge two blocks\n * @param {Block} targetBlock - previous block will be append to this block\n * @param {Block} blockToMerge - block that will be merged with target block\n *\n * @return {Promise} - the sequence that can be continued\n */\n mergeBlocks(targetBlock, blockToMerge) {\n let blockToMergeIndex = this._blocks.indexOf(blockToMerge);\n\n return Promise.resolve()\n .then( () => {\n if (blockToMerge.isEmpty) {\n return;\n }\n\n return blockToMerge.data\n .then((blockToMergeInfo) => {\n targetBlock.mergeWith(blockToMergeInfo.data);\n });\n })\n .then( () => {\n this.removeBlock(blockToMergeIndex);\n this.currentBlockIndex = this._blocks.indexOf(targetBlock);\n });\n }\n\n /**\n * Remove block with passed index or remove last\n * @param {Number|null} index\n */\n removeBlock(index) {\n if (!index) {\n index = this.currentBlockIndex;\n }\n this._blocks.remove(index);\n }\n\n /**\n * Split current Block\n * 1. Extract content from Caret position to the Block`s end\n * 2. Insert a new Block below current one with extracted content\n */\n split() {\n let extractedFragment = this.Editor.Caret.extractFragmentFromCaretPosition(),\n wrapper = $.make('div');\n\n wrapper.append(extractedFragment);\n\n /**\n * @todo make object in accordance with Tool\n */\n let data = {\n text: $.isEmpty(wrapper) ? '' : wrapper.innerHTML,\n };\n\n /**\n * Renew current Block\n * @type {Block}\n */\n const blockInserted = this.insert(this.config.initialBlock, data);\n\n this.currentNode = blockInserted.pluginsContent;\n }\n\n /**\n * Replace current working block\n *\n * @param {String} toolName — plugin name\n * @param {Object} data — plugin data\n */\n replace(toolName, data = {}) {\n let block = this.composeBlock(toolName, data);\n\n this._blocks.insert(this.currentBlockIndex, block, true);\n }\n\n /**\n * returns last Block\n * @return {Block}\n */\n get lastBlock() {\n return this._blocks[this._blocks.length - 1];\n }\n\n /**\n * Returns Block by passed index\n * @param {Number} index\n * @return {Block}\n */\n getBlockByIndex(index) {\n return this._blocks[index];\n }\n\n /**\n * Get Block instance by html element\n * @param {Node} element\n * @returns {Block}\n */\n getBlock(element) {\n if (!$.isElement(element)) {\n element = element.parentNode;\n }\n\n let nodes = this._blocks.nodes,\n firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`),\n index = nodes.indexOf(firstLevelBlock);\n\n if (index >= 0) {\n return this._blocks[index];\n }\n }\n\n /**\n * Get current Block instance\n *\n * @return {Block}\n */\n get currentBlock() {\n return this._blocks[this.currentBlockIndex];\n }\n\n /**\n * Returns next Block instance\n * @return {Block|null}\n */\n get nextBlock() {\n let isLastBlock = this.currentBlockIndex === (this._blocks.length - 1);\n\n if (isLastBlock) {\n return null;\n }\n\n return this._blocks[this.currentBlockIndex + 1];\n }\n\n /**\n * Returns previous Block instance\n * @return {Block|null}\n */\n get previousBlock() {\n let isFirstBlock = this.currentBlockIndex === 0;\n\n if (isFirstBlock) {\n return null;\n }\n\n return this._blocks[this.currentBlockIndex - 1];\n }\n\n /**\n * Get working html element\n *\n * @return {HTMLElement}\n */\n get currentNode() {\n return this._blocks.nodes[this.currentBlockIndex];\n }\n\n /**\n * Set currentBlockIndex to passed block\n * @param {HTMLElement} element\n */\n set currentNode(element) {\n let nodes = this._blocks.nodes,\n firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`);\n\n /**\n * Update current Block's index\n * @type {number}\n */\n this.currentBlockIndex = nodes.indexOf(firstLevelBlock);\n\n /**\n * Remove previous selected Block's state\n */\n this.blocks.forEach( block => block.selected = false);\n\n /**\n * Mark current Block as selected\n * @type {boolean}\n */\n this.currentBlock.selected = true;\n }\n\n /**\n * Get array of Block instances\n *\n * @returns {Block[]} {@link Blocks#array}\n */\n get blocks() {\n return this._blocks.array;\n }\n\n /**\n * 1) Find first-level Block from passed child Node\n * 2) Mark it as current\n *\n * @param {Element|Text} childNode - look ahead from this node.\n * @throws Error - when passed Node is not included at the Block\n */\n setCurrentBlockByChildNode(childNode) {\n /**\n * If node is Text TextNode\n */\n if (!$.isElement(childNode)) {\n childNode = childNode.parentNode;\n }\n\n let parentFirstLevelBlock = childNode.closest(`.${Block.CSS.wrapper}`);\n\n if (parentFirstLevelBlock) {\n this.currentNode = parentFirstLevelBlock;\n } else {\n throw new Error('Can not find a Block from this child Node');\n }\n }\n\n /**\n * Swap Blocks Position\n * @param {Number} fromIndex\n * @param {Number} toIndex\n */\n swap(fromIndex, toIndex) {\n /** Move up current Block */\n this._blocks.swap(fromIndex, toIndex);\n\n /** Now actual block moved up so that current block index decreased */\n this.currentBlockIndex = toIndex;\n }\n /**\n * Clears Editor\n * @param {boolean} needAddInitialBlock - 1) in internal calls (for example, in api.blocks.render)\n * we don't need to add empty initial block\n * 2) in api.blocks.clear we should add empty block\n */\n clear(needAddInitialBlock = false) {\n this._blocks.removeAll();\n this.currentBlockIndex = -1;\n\n if (needAddInitialBlock) {\n this.insert(this.config.initialBlock);\n }\n }\n};\n\n/**\n * @class Blocks\n * @classdesc Class to work with Block instances array\n *\n * @private\n *\n * @property {HTMLElement} workingArea — editor`s working node\n *\n */\nclass Blocks {\n /**\n * @constructor\n *\n * @param {HTMLElement} workingArea — editor`s working node\n */\n constructor(workingArea) {\n this.blocks = [];\n this.workingArea = workingArea;\n }\n\n /**\n * Push back new Block\n *\n * @param {Block} block\n */\n push(block) {\n this.blocks.push(block);\n this.workingArea.appendChild(block.html);\n }\n\n /**\n * Swaps blocks with indexes first and second\n * @param {Number} first - first block index\n * @param {Number} second - second block index\n */\n swap(first, second) {\n let secondBlock = this.blocks[second];\n\n /**\n * Change in DOM\n */\n $.swap(this.blocks[first].html, secondBlock.html);\n\n /**\n * Change in array\n */\n this.blocks[second] = this.blocks[first];\n this.blocks[first] = secondBlock;\n }\n\n /**\n * Insert new Block at passed index\n *\n * @param {Number} index — index to insert Block\n * @param {Block} block — Block to insert\n * @param {Boolean} replace — it true, replace block on given index\n */\n insert(index, block, replace = false) {\n if (!this.length) {\n this.push(block);\n return;\n }\n\n if (index > this.length) {\n index = this.length;\n }\n\n if (replace) {\n this.blocks[index].html.remove();\n }\n\n let deleteCount = replace ? 1 : 0;\n\n this.blocks.splice(index, deleteCount, block);\n\n if (index > 0) {\n let previousBlock = this.blocks[index - 1];\n\n previousBlock.html.insertAdjacentElement('afterend', block.html);\n } else {\n let nextBlock = this.blocks[index + 1];\n\n if (nextBlock) {\n nextBlock.html.insertAdjacentElement('beforebegin', block.html);\n } else {\n this.workingArea.appendChild(block.html);\n }\n }\n }\n\n /**\n * Remove block\n * @param {Number|null} index\n */\n remove(index) {\n if (isNaN(index)) {\n index = this.length - 1;\n }\n\n this.blocks[index].html.remove();\n this.blocks.splice(index, 1);\n }\n\n /**\n * Remove all blocks\n */\n removeAll() {\n this.workingArea.innerHTML = '';\n this.blocks.length = 0;\n }\n\n /**\n * Insert Block after passed target\n *\n * @todo decide if this method is necessary\n *\n * @param {Block} targetBlock — target after wich Block should be inserted\n * @param {Block} newBlock — Block to insert\n */\n insertAfter(targetBlock, newBlock) {\n let index = this.blocks.indexOf(targetBlock);\n\n this.insert(index + 1, newBlock);\n }\n\n /**\n * Get Block by index\n *\n * @param {Number} index — Block index\n * @returns {Block}\n */\n get(index) {\n return this.blocks[index];\n }\n\n /**\n * Return index of passed Block\n *\n * @param {Block} block\n * @returns {Number}\n */\n indexOf(block) {\n return this.blocks.indexOf(block);\n }\n\n /**\n * Get length of Block instances array\n *\n * @returns {Number}\n */\n get length() {\n return this.blocks.length;\n }\n\n /**\n * Get Block instances array\n *\n * @returns {Block[]}\n */\n get array() {\n return this.blocks;\n }\n\n /**\n * Get blocks html elements array\n *\n * @returns {HTMLElement[]}\n */\n get nodes() {\n return _.array(this.workingArea.children);\n }\n\n /**\n * Proxy trap to implement array-like setter\n *\n * @example\n * blocks[0] = new Block(...)\n *\n * @param {Blocks} instance — Blocks instance\n * @param {Number|String} index — block index\n * @param {Block} block — Block to set\n * @returns {Boolean}\n */\n static set(instance, index, block) {\n if (isNaN(Number(index))) {\n return false;\n }\n\n instance.insert(index, block);\n\n return true;\n }\n\n /**\n * Proxy trap to implement array-like getter\n *\n * @param {Blocks} instance — Blocks instance\n * @param {Number|String} index — Block index\n * @returns {Block|*}\n */\n static get(instance, index) {\n if (isNaN(Number(index))) {\n return instance[index];\n }\n\n return instance.get(index);\n }\n}\n","/**\n * @class Caret\n * @classdesc Contains methods for working Caret\n *\n * Uses Range methods to manipulate with caret\n *\n * @module Caret\n *\n * @version 2.0.0\n */\n\nimport Selection from '../selection';\n\n/**\n * @typedef {Caret} Caret\n */\nexport default class Caret extends Module {\n /**\n * @constructor\n */\n constructor({config}) {\n super({config});\n }\n\n /**\n * Method gets Block instance and puts caret to the text node with offset\n * There two ways that method applies caret position:\n * - first found text node: sets at the beginning, but you can pass an offset\n * - last found text node: sets at the end of the node. Also, you can customize the behaviour\n *\n * @param {Block} block - Block class\n * @param {Number} offset - caret offset regarding to the text node\n * @param {Boolean} atEnd - put caret at the end of the text node or not\n */\n setToBlock(block, offset = 0, atEnd = false) {\n let element = block.pluginsContent;\n\n /** If Element is INPUT */\n if ($.isNativeInput(element)) {\n element.focus();\n return;\n }\n\n let nodeToSet = $.getDeepestNode(element, atEnd);\n\n if (atEnd || offset > nodeToSet.length) {\n offset = nodeToSet.length;\n }\n\n /** if found deepest node is native input */\n if ($.isNativeInput(nodeToSet)) {\n nodeToSet.focus();\n return;\n }\n\n /**\n * @todo try to fix via Promises or use querySelectorAll to not to use timeout\n */\n _.delay( () => {\n this.set(nodeToSet, offset);\n }, 20)();\n\n this.Editor.BlockManager.currentNode = block.wrapper;\n }\n\n /**\n * Creates Document Range and sets caret to the element with offset\n * @param {Element} element - target node.\n * @param {Number} offset - offset\n */\n set( element, offset = 0) {\n let range = document.createRange(),\n selection = Selection.get();\n\n range.setStart(element, offset);\n range.setEnd(element, offset);\n\n selection.removeAllRanges();\n selection.addRange(range);\n };\n\n /**\n * Set Caret to the last Block\n * If last block is not empty, append another empty block\n */\n setToTheLastBlock() {\n let lastBlock = this.Editor.BlockManager.lastBlock;\n\n if (!lastBlock) return;\n\n /**\n * If last block is empty and it is an initialBlock, set to that.\n * Otherwise, append new empty block and set to that\n */\n if (lastBlock.isEmpty) {\n this.setToBlock(lastBlock);\n } else {\n this.Editor.BlockManager.insert(this.config.initialBlock);\n }\n }\n\n /**\n * Extract content fragment of current Block from Caret position to the end of the Block\n */\n extractFragmentFromCaretPosition() {\n let selection = Selection.get();\n\n if (selection.rangeCount) {\n let selectRange = selection.getRangeAt(0),\n blockElem = this.Editor.BlockManager.currentBlock.pluginsContent;\n\n selectRange.deleteContents();\n\n if (blockElem) {\n let range = selectRange.cloneRange(true);\n\n range.selectNodeContents(blockElem);\n range.setStart(selectRange.endContainer, selectRange.endOffset);\n return range.extractContents();\n }\n }\n }\n\n /**\n * Get all first-level (first child of [contenteditabel]) siblings from passed node\n * Then you can check it for emptiness\n *\n * @example\n *

    \n *

    |\n *

    | left first-level siblings\n *

    |\n *
    adaddad
    <-- passed node for example \n *

    |\n *

    | right first-level siblings\n *

    |\n *
    \n *\n * @return {Element[]}\n */\n getHigherLevelSiblings(from, direction ) {\n let current = from,\n siblings = [];\n\n /**\n * Find passed node's firs-level parent (in example - blockquote)\n */\n while (current.parentNode && current.parentNode.contentEditable !== 'true') {\n current = current.parentNode;\n }\n\n let sibling = direction === 'left' ? 'previousSibling' : 'nextSibling';\n\n /**\n * Find all left/right siblings\n */\n while (current[sibling]) {\n current = current[sibling];\n siblings.push(current);\n }\n\n return siblings;\n }\n\n /**\n * Set's caret to the next Block\n * Before moving caret, we should check if caret position is at the end of Plugins node\n * Using {@link Dom#getDeepestNode} to get a last node and match with current selection\n *\n * @param {Boolean} force - force navigation even if caret is not at the end\n *\n * @return {Boolean}\n */\n navigateNext(force = false) {\n let nextBlock = this.Editor.BlockManager.nextBlock;\n\n if (!nextBlock) {\n return false;\n }\n\n if (force || this.isAtEnd) {\n this.setToBlock(nextBlock);\n return true;\n }\n\n return false;\n }\n\n /**\n * Set's caret to the previous Block\n * Before moving caret, we should check if caret position is start of the Plugins node\n * Using {@link Dom#getDeepestNode} to get a last node and match with current selection\n *\n * @param {Boolean} force - force navigation even if caret is not at the start\n *\n * @return {Boolean}\n */\n navigatePrevious(force = false) {\n let previousBlock = this.Editor.BlockManager.previousBlock;\n\n if (!previousBlock) {\n return false;\n }\n\n if (force || this.isAtStart) {\n this.setToBlock( previousBlock, 0, true );\n return true;\n }\n\n return false;\n }\n\n /**\n * Get's deepest first node and checks if offset is zero\n * @return {boolean}\n */\n get isAtStart() {\n /**\n * Don't handle ranges\n */\n if (!Selection.isCollapsed) {\n return false;\n }\n\n let selection = Selection.get(),\n anchorNode = selection.anchorNode,\n firstNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.pluginsContent);\n\n /**\n * Workaround case when caret in the text like \" |Hello!\"\n * selection.anchorOffset is 1, but real caret visible position is 0\n * @type {number}\n */\n let firstLetterPosition = anchorNode.textContent.search(/\\S/);\n\n if (firstLetterPosition === -1) { // empty text\n firstLetterPosition = 0;\n }\n\n /**\n * In case of\n *
    \n *

    <-- first (and deepest) node is \n * |adaddad <-- anchor node\n *
    \n */\n if ($.isEmpty(firstNode)) {\n let leftSiblings = this.getHigherLevelSiblings(anchorNode, 'left'),\n nothingAtLeft = leftSiblings.every( node => $.isEmpty(node) );\n\n\n\n if (nothingAtLeft && selection.anchorOffset === firstLetterPosition) {\n return true;\n }\n }\n\n /**\n * We use <= comparison for case:\n * \"| Hello\" <--- selection.anchorOffset is 0, but firstLetterPosition is 1\n */\n return firstNode === null || anchorNode === firstNode && selection.anchorOffset <= firstLetterPosition;\n }\n\n /**\n * Get's deepest last node and checks if offset is last node text length\n * @return {boolean}\n */\n get isAtEnd() {\n /**\n * Don't handle ranges\n */\n if (!Selection.isCollapsed) {\n return false;\n }\n\n let selection = Selection.get(),\n anchorNode = selection.anchorNode,\n lastNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.pluginsContent, true);\n\n /**\n * In case of\n *
    \n * adaddad| <-- anchor node\n *

    <-- first (and deepest) node is \n *
    \n */\n if ($.isEmpty(lastNode)) {\n let leftSiblings = this.getHigherLevelSiblings(anchorNode, 'right'),\n nothingAtRight = leftSiblings.every( node => $.isEmpty(node) );\n\n if (nothingAtRight && selection.anchorOffset === anchorNode.textContent.length) {\n return true;\n }\n }\n\n /**\n * Workaround case:\n * hello | <--- anchorOffset will be 5, but textContent.length will be 6.\n * Why not regular .trim():\n * in case of ' hello |' trim() will also remove space at the beginning, so length will be lower than anchorOffset\n */\n let rightTrimmedText = lastNode.textContent.replace(/\\s+$/, '');\n\n /**\n * We use >= comparison for case:\n * \"Hello |\" <--- selection.anchorOffset is 7, but rightTrimmedText is 6\n */\n return anchorNode === lastNode && selection.anchorOffset >= rightTrimmedText.length;\n }\n}\n","/**\n * @module eventDispatcher\n *\n * Has two important methods:\n * - {Function} on - appends subscriber to the event. If event doesn't exist - creates new one\n * - {Function} emit - fires all subscribers with data\n * - {Function off - unsubsribes callback\n *\n * @version 1.0.0\n *\n * @typedef {Events} Events\n * @property {Object} subscribers - all subscribers grouped by event name\n */\nexport default class Events extends Module {\n /**\n * @constructor\n */\n constructor({config}) {\n super({config});\n this.subscribers = {};\n }\n\n /**\n * Subscribe any event on callback\n *\n * @param {String} eventName - event name\n * @param {Function} callback - subscriber\n */\n on(eventName, callback) {\n if (!(eventName in this.subscribers)) {\n this.subscribers[eventName] = [];\n }\n\n // group by events\n this.subscribers[eventName].push(callback);\n }\n\n /**\n * Emit callbacks with passed data\n *\n * @param {String} eventName - event name\n * @param {Object} data - subscribers get this data when they were fired\n */\n emit(eventName, data) {\n if (!this.subscribers[eventName]) {\n return;\n }\n\n this.subscribers[eventName].reduce(function (previousData, currentHandler) {\n let newData = currentHandler(previousData);\n\n return newData ? newData : previousData;\n }, data);\n }\n\n /**\n * Unsubsribe callback from event\n *\n * @param eventName\n * @param callback\n */\n off(eventName, callback) {\n for(let i = 0; i < this.subscribers[eventName].length; i++) {\n if (this.subscribers[eventName][i] === callback) {\n delete this.subscribers[eventName][i];\n break;\n }\n }\n }\n\n /**\n * Destroyer\n * clears subsribers list\n */\n destroy() {\n this.subscribers = null;\n }\n}\n","/**\n * Codex Editor Listeners module\n *\n * @module Listeners\n *\n * Module-decorator for event listeners assignment\n *\n * @author Codex Team\n * @version 2.0.0\n */\n\n/**\n * @typedef {Listeners} Listeners\n * @property {Array} allListeners\n */\nexport default class Listeners extends Module {\n /**\n * @constructor\n * @param {EditorConfig} config\n */\n constructor({config}) {\n super({config});\n this.allListeners = [];\n }\n\n /**\n * Assigns event listener on element\n *\n * @param {Element} element - DOM element that needs to be listened\n * @param {String} eventType - event type\n * @param {Function} handler - method that will be fired on event\n * @param {Boolean} useCapture - use event bubbling\n */\n on(element, eventType, handler, useCapture = false) {\n let assignedEventData = {\n element,\n eventType,\n handler,\n useCapture\n };\n\n let alreadyExist = this.findOne(element, eventType, handler);\n\n if (alreadyExist) return;\n\n this.allListeners.push(assignedEventData);\n element.addEventListener(eventType, handler, useCapture);\n }\n\n /**\n * Removes event listener from element\n *\n * @param {Element} element - DOM element that we removing listener\n * @param {String} eventType - event type\n * @param {Function} handler - remove handler, if element listens several handlers on the same event type\n * @param {Boolean} useCapture - use event bubbling\n */\n off(element, eventType, handler, useCapture = false) {\n let existingListeners = this.findAll(element, eventType, handler);\n\n for (let i = 0; i < existingListeners.length; i++) {\n let index = this.allListeners.indexOf(existingListeners[i]);\n\n if (index > 0) {\n this.allListeners.splice(index, 1);\n }\n }\n\n element.removeEventListener(eventType, handler, useCapture);\n }\n\n /**\n * Search method: looks for listener by passed element\n * @param {Element} element - searching element\n * @returns {Array} listeners that found on element\n */\n findByElement(element) {\n let listenersOnElement = [];\n\n for (let i = 0; i < this.allListeners.length; i++) {\n let listener = this.allListeners[i];\n\n if (listener.element === element) {\n listenersOnElement.push(listener);\n }\n }\n\n return listenersOnElement;\n }\n\n /**\n * Search method: looks for listener by passed event type\n * @param {String} eventType\n * @return {Array} listeners that found on element\n */\n findByType(eventType) {\n let listenersWithType = [];\n\n for (let i = 0; i < this.allListeners.length; i++) {\n let listener = this.allListeners[i];\n\n if (listener.type === eventType) {\n listenersWithType.push(listener);\n }\n }\n\n return listenersWithType;\n }\n\n /**\n * Search method: looks for listener by passed handler\n * @param {Function} handler\n * @return {Array} listeners that found on element\n */\n findByHandler(handler) {\n let listenersWithHandler = [];\n\n for (let i = 0; i < this.allListeners.length; i++) {\n let listener = this.allListeners[i];\n\n if (listener.handler === handler) {\n listenersWithHandler.push(listener);\n }\n }\n\n return listenersWithHandler;\n }\n\n /**\n * @param {Element} element\n * @param {String} eventType\n * @param {Function} handler\n * @return {Element|null}\n */\n findOne(element, eventType, handler) {\n let foundListeners = this.findAll(element, eventType, handler);\n\n return foundListeners.length > 0 ? foundListeners[0] : null;\n }\n\n /**\n * @param {Element} element\n * @param {String} eventType\n * @param {Function} handler\n * @return {Array}\n */\n findAll(element, eventType, handler) {\n let found,\n foundByElements = element ? this.findByElement(element) : [];\n // foundByEventType = eventType ? this.findByType(eventType) : [],\n // foundByHandler = handler ? this.findByHandler(handler) : [];\n\n if (element && eventType && handler) {\n found = foundByElements.filter( event => event.eventType === eventType && event.handler === handler );\n } else if (element && eventType) {\n found = foundByElements.filter( event => event.eventType === eventType);\n } else {\n found = foundByElements;\n }\n\n return found;\n }\n\n /**\n * Removes all listeners\n */\n removeAll() {\n this.allListeners.map( (current) => {\n current.element.removeEventListener(current.eventType, current.handler);\n });\n\n this.allListeners = [];\n }\n}\n","/**\n * Codex Editor Renderer Module\n *\n * @module Renderer\n * @author CodeX Team\n *\n * @version 2.0.0\n */\nexport default class Renderer extends Module {\n /**\n * @constructor\n * @param {EditorConfig} config\n */\n constructor({config}) {\n super({config});\n }\n\n /**\n * @typedef {Object} RendererItems\n * @property {String} type - tool name\n * @property {Object} data - tool data\n */\n\n /**\n * @example\n *\n * items: [\n * {\n * type : 'paragraph',\n * data : {\n * text : 'Hello from Codex!'\n * }\n * },\n * {\n * type : 'paragraph',\n * data : {\n * text : 'Leave feedback if you like it!'\n * }\n * },\n * ]\n *\n */\n\n /**\n * Make plugin blocks from array of plugin`s data\n * @param {RendererItems[]} items\n */\n render(items) {\n let chainData = [];\n\n for (let i = 0; i < items.length; i++) {\n chainData.push({\n function: () => this.insertBlock(items[i])\n });\n }\n\n return _.sequence(chainData);\n }\n\n /**\n * Get plugin instance\n * Add plugin instance to BlockManager\n * Insert block to working zone\n *\n * @param {Object} item\n * @returns {Promise.}\n * @private\n */\n insertBlock(item) {\n let tool = item.type,\n data = item.data,\n settings = item.settings;\n\n if (tool in this.Editor.Tools.available) {\n this.Editor.BlockManager.insert(tool, data, settings);\n } else {\n /**\n * @todo show warning notification message\n *\n * `${tool} blocks was skipped.`\n */\n\n _.log(`Tool «${tool}» is not found. Check 'tools' property at your initial CodeX Editor config.`, 'warn');\n }\n\n return Promise.resolve();\n }\n}\n","/**\n * CodeX Sanitizer\n *\n * @module Sanitizer\n * Clears HTML from taint tags\n *\n * @version 2.0.0\n *\n * @example\n * Module can be used within two ways:\n * 1) When you have an instance\n * - this.Editor.Sanitizer.clean(yourTaintString);\n * 2) As static method\n * - CodexEditor.Sanitizer.clean(yourTaintString, yourCustomConfiguration);\n *\n * {@link SanitizerConfig}\n */\n\n\n/**\n * @typedef {Object} SanitizerConfig\n * @property {Object} tags - define tags restrictions\n *\n * @example\n *\n * tags : {\n * p: true,\n * a: {\n * href: true,\n * rel: \"nofollow\",\n * target: \"_blank\"\n * }\n * }\n */\nexport default class Sanitizer extends Module {\n /**\n * Initializes Sanitizer module\n * Sets default configuration if custom not exists\n *\n * @property {SanitizerConfig} this.defaultConfig\n * @property {HTMLJanitor} this._sanitizerInstance - Sanitizer library\n *\n * @param {SanitizerConfig} config\n */\n constructor({config}) {\n super({config});\n\n // default config\n this.defaultConfig = null;\n this._sanitizerInstance = null;\n\n /** Custom configuration */\n this.sanitizerConfig = config.settings ? config.settings.sanitizer : {};\n\n /** HTML Janitor library */\n this.sanitizerInstance = require('html-janitor');\n }\n\n /**\n * If developer uses editor's API, then he can customize sanitize restrictions.\n * Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere\n * At least, if there is no config overrides, that API uses Default configuration\n *\n * @uses https://www.npmjs.com/package/html-janitor\n *\n * @param {HTMLJanitor} library - sanitizer extension\n */\n set sanitizerInstance(library) {\n this._sanitizerInstance = new library(this.defaultConfig);\n }\n\n /**\n * Sets sanitizer configuration. Uses default config if user didn't pass the restriction\n * @param {SanitizerConfig} config\n */\n set sanitizerConfig(config) {\n if (_.isEmpty(config)) {\n this.defaultConfig = {\n tags: {\n p: {},\n a: {\n href: true,\n target: '_blank',\n rel: 'nofollow'\n }\n }\n };\n } else {\n this.defaultConfig = config;\n }\n }\n\n /**\n * Cleans string from unwanted tags\n * @param {String} taintString - HTML string\n * @param {Object} customConfig - custom sanitizer configuration. Method uses default if param is empty\n * @return {String} clean HTML\n */\n clean(taintString, customConfig = {}) {\n if (_.isEmpty(customConfig)) {\n return this._sanitizerInstance.clean(taintString);\n } else {\n return Sanitizer.clean(taintString, customConfig);\n }\n }\n\n /**\n * Cleans string from unwanted tags\n * @static\n *\n * Method allows to use default config\n *\n * @param {String} taintString - taint string\n * @param {SanitizerConfig} customConfig - allowed tags\n *\n * @return {String} clean HTML\n */\n static clean(taintString, customConfig) {\n let newInstance = Sanitizer(customConfig);\n\n return newInstance.clean(taintString);\n }\n}\n","/**\n * Codex Editor Saver\n *\n * @module Saver\n * @author Codex Team\n * @version 2.0.0\n */\n\n/**\n * @typedef {Object} SavedData\n * @property {Date} time - saving proccess time\n * @property {Object} items - extracted data\n * @property {String} version - CodexEditor version\n */\n\n/**\n * @classdesc This method reduces all Blocks asyncronically and calls Block's save method to extract data\n *\n * @typedef {Saver} Saver\n * @property {Element} html - Editor HTML content\n * @property {String} json - Editor JSON output\n */\nexport default class Saver extends Module {\n /**\n * @constructor\n * @param config\n */\n constructor({config}) {\n super({config});\n\n this.output = null;\n this.blocksData = [];\n }\n\n /**\n * Composes new chain of Promises to fire them alternatelly\n * @return {SavedData}\n */\n save() {\n let blocks = this.Editor.BlockManager.blocks,\n chainData = [];\n\n blocks.forEach((block) => {\n chainData.push(block.data);\n });\n\n return Promise.all(chainData)\n .then((allExtractedData) => this.makeOutput(allExtractedData))\n .then((outputData) => {\n return outputData;\n });\n }\n\n /**\n * Creates output object with saved data, time and version of editor\n * @param {Object} allExtractedData\n * @return {SavedData}\n */\n makeOutput(allExtractedData) {\n let items = [],\n totalTime = 0;\n\n console.groupCollapsed('[CodexEditor saving]:');\n\n allExtractedData.forEach((extraction) => {\n /** Group process info */\n console.log(`«${extraction.tool}» saving info`, extraction);\n totalTime += extraction.time;\n items.push({\n type: extraction.tool,\n data: extraction.data\n });\n });\n\n console.log('Total', totalTime);\n console.groupEnd();\n\n return {\n time : +new Date(),\n items : items,\n version : VERSION,\n };\n }\n}\n\n// module.exports = (function (saver) {\n//\n// let editor = codex.editor;\n//\n// /**\n// * @public\n// * Save blocks\n// */\n// saver.save = function () {\n//\n// /** Save html content of redactor to memory */\n// editor.state.html = editor.nodes.redactor.innerHTML;\n//\n// /** Clean jsonOutput state */\n// editor.state.jsonOutput = [];\n//\n// return saveBlocks(editor.nodes.redactor.childNodes);\n//\n// };\n//\n// /**\n// * @private\n// * Save each block data\n// *\n// * @param blocks\n// * @returns {Promise.}\n// */\n// let saveBlocks = function (blocks) {\n//\n// let data = [];\n//\n// for(let index = 0; index < blocks.length; index++) {\n//\n// data.push(getBlockData(blocks[index]));\n//\n// }\n//\n// return Promise.all(data)\n// .then(makeOutput)\n// .catch(editor.core.log);\n//\n// };\n//\n// /** Save and validate block data */\n// let getBlockData = function (block) {\n//\n// return saveBlockData(block)\n// .then(validateBlockData)\n// .catch(editor.core.log);\n//\n// };\n//\n// /**\n// * @private\n// * Call block`s plugin save method and return saved data\n// *\n// * @param block\n// * @returns {Object}\n// */\n// let saveBlockData = function (block) {\n//\n// let pluginName = block.dataset.tool;\n//\n// /** Check for plugin existence */\n// if (!editor.tools[pluginName]) {\n//\n// editor.core.log(`Plugin «${pluginName}» not found`, 'error');\n// return {data: null, pluginName: null};\n//\n// }\n//\n// /** Check for plugin having save method */\n// if (typeof editor.tools[pluginName].save !== 'function') {\n//\n// editor.core.log(`Plugin «${pluginName}» must have save method`, 'error');\n// return {data: null, pluginName: null};\n//\n// }\n//\n// /** Result saver */\n// let blockContent = block.childNodes[0],\n// pluginsContent = blockContent.childNodes[0],\n// position = pluginsContent.dataset.inputPosition;\n//\n// /** If plugin wasn't available then return data from cache */\n// if ( editor.tools[pluginName].available === false ) {\n//\n// return Promise.resolve({data: codex.editor.state.blocks.items[position].data, pluginName});\n//\n// }\n//\n// return Promise.resolve(pluginsContent)\n// .then(editor.tools[pluginName].save)\n// .then(data => Object({data, pluginName}));\n//\n// };\n//\n// /**\n// * Call plugin`s validate method. Return false if validation failed\n// *\n// * @param data\n// * @param pluginName\n// * @returns {Object|Boolean}\n// */\n// let validateBlockData = function ({data, pluginName}) {\n//\n// if (!data || !pluginName) {\n//\n// return false;\n//\n// }\n//\n// if (editor.tools[pluginName].validate) {\n//\n// let result = editor.tools[pluginName].validate(data);\n//\n// /**\n// * Do not allow invalid data\n// */\n// if (!result) {\n//\n// return false;\n//\n// }\n//\n// }\n//\n// return {data, pluginName};\n//\n//\n// };\n//\n// /**\n// * Compile article output\n// *\n// * @param savedData\n// * @returns {{time: number, version, items: (*|Array)}}\n// */\n// let makeOutput = function (savedData) {\n//\n// savedData = savedData.filter(blockData => blockData);\n//\n// let items = savedData.map(blockData => Object({type: blockData.pluginName, data: blockData.data}));\n//\n// editor.state.jsonOutput = items;\n//\n// return {\n// id: editor.state.blocks.id || null,\n// time: +new Date(),\n// version: editor.version,\n// items\n// };\n//\n// };\n//\n// return saver;\n//\n// })({});\n","/**\n * Block Settings\n *\n * ____ Settings Panel ____\n * | ...................... |\n * | . Tool Settings . |\n * | ...................... |\n * | . Default Settings . |\n * | ...................... |\n * |________________________|\n */\nexport default class BlockSettings extends Module {\n /**\n * @constructor\n */\n constructor({config}) {\n super({config});\n\n this.nodes = {\n wrapper: null,\n toolSettings: null,\n defaultSettings: null\n };\n }\n\n /**\n * Module Events\n * @return {{opened: string, closed: string}}\n */\n get events() {\n return {\n opened: 'block-settings-opened',\n closed: 'block-settings-closed',\n };\n }\n\n /**\n * Block Settings CSS\n * @return {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}}\n */\n static get CSS() {\n return {\n // Settings Panel\n wrapper: 'ce-settings',\n wrapperOpened: 'ce-settings--opened',\n toolSettings: 'ce-settings__plugin-zone',\n defaultSettings: 'ce-settings__default-zone',\n\n button: 'ce-settings__button'\n };\n }\n\n /**\n * Panel with block settings with 2 sections:\n * - Tool's Settings\n * - Default Settings [Move, Remove, etc]\n *\n * @return {Element}\n */\n make() {\n this.nodes.wrapper = $.make('div', BlockSettings.CSS.wrapper);\n\n this.nodes.toolSettings = $.make('div', BlockSettings.CSS.toolSettings);\n this.nodes.defaultSettings = $.make('div', BlockSettings.CSS.defaultSettings);\n\n $.append(this.nodes.wrapper, [this.nodes.toolSettings, this.nodes.defaultSettings]);\n }\n\n /**\n * Add Tool's settings\n */\n addToolSettings() {\n if (typeof this.Editor.BlockManager.currentBlock.tool.makeSettings === 'function') {\n $.append(this.nodes.toolSettings, this.Editor.BlockManager.currentBlock.tool.makeSettings());\n }\n }\n\n /**\n * Add default settings\n */\n addDefaultSettings() {\n $.append(this.nodes.defaultSettings, this.Editor.BlockManager.currentBlock.renderTunes());\n }\n\n /**\n * Is Block Settings opened or not\n * @returns {boolean}\n */\n get opened() {\n return this.nodes.wrapper.classList.contains(BlockSettings.CSS.wrapperOpened);\n }\n\n /**\n * Open Block Settings pane\n */\n open() {\n this.nodes.wrapper.classList.add(BlockSettings.CSS.wrapperOpened);\n\n /**\n * Fill Tool's settings\n */\n this.addToolSettings();\n\n /**\n * Add default settings that presents for all Blocks\n */\n this.addDefaultSettings();\n\n /** Tell to subscribers that block settings is opened */\n this.Editor.Events.emit(this.events.opened);\n }\n\n /**\n * Close Block Settings pane\n */\n close() {\n this.nodes.wrapper.classList.remove(BlockSettings.CSS.wrapperOpened);\n\n /** Clear settings */\n this.nodes.toolSettings.innerHTML = '';\n this.nodes.defaultSettings.innerHTML = '';\n\n /** Tell to subscribers that block settings is closed */\n this.Editor.Events.emit(this.events.closed);\n }\n}\n","import BoldInlineTool from '../inline-tools/inline-tool-bold';\nimport ItalicInlineTool from '../inline-tools/inline-tool-italic';\nimport LinkInlineTool from '../inline-tools/inline-tool-link';\nimport Selection from '../selection';\nexport default class InlineToolbar extends Module {\n /**\n * @constructor\n */\n constructor({ config }) {\n super({ config });\n /**\n * CSS styles\n */\n this.CSS = {\n inlineToolbar: 'ce-inline-toolbar',\n inlineToolbarShowed: 'ce-inline-toolbar--showed',\n buttonsWrapper: 'ce-inline-toolbar__buttons',\n actionsWrapper: 'ce-inline-toolbar__actions',\n };\n /**\n * Inline Toolbar elements\n */\n this.nodes = {\n wrapper: null,\n buttons: null,\n /**\n * Zone below the buttons where Tools can create additional actions by 'renderActions()' method\n * For example, input for the 'link' tool or textarea for the 'comment' tool\n */\n actions: null,\n };\n /**\n * Margin above/below the Toolbar\n */\n this.toolbarVerticalMargin = 20;\n }\n /**\n * Inline Toolbar Tools\n * @todo Merge internal tools with external\n */\n get tools() {\n if (!this.toolsInstances) {\n this.toolsInstances = [\n new BoldInlineTool(this.Editor.API.methods),\n new ItalicInlineTool(this.Editor.API.methods),\n new LinkInlineTool(this.Editor.API.methods),\n ...this.Editor.Tools.inline.map((Tool) => new Tool(this.Editor.API.methods)),\n ];\n }\n return this.toolsInstances;\n }\n /**\n * Making DOM\n */\n make() {\n this.nodes.wrapper = $.make('div', this.CSS.inlineToolbar);\n this.nodes.buttons = $.make('div', this.CSS.buttonsWrapper);\n this.nodes.actions = $.make('div', this.CSS.actionsWrapper);\n /**\n * Append Inline Toolbar to the Editor\n */\n $.append(this.nodes.wrapper, [this.nodes.buttons, this.nodes.actions]);\n $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);\n /**\n * Append Inline Toolbar Tools\n */\n this.addTools();\n }\n /**\n *\n *\n * Moving / appearance\n * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n *\n */\n /**\n * Shows Inline Toolbar by keyup/mouseup\n * @param {KeyboardEvent|MouseEvent} event\n */\n handleShowingEvent(event) {\n if (!this.allowedToShow(event)) {\n this.close();\n return;\n }\n this.move();\n this.open();\n /** Check Tools state for selected fragment */\n this.checkToolsState();\n }\n /**\n * Move Toolbar to the selected text\n */\n move() {\n const selectionRect = Selection.rect;\n const wrapperOffset = this.Editor.UI.nodes.wrapper.getBoundingClientRect();\n const newCoords = {\n x: selectionRect.x - wrapperOffset.left,\n y: selectionRect.y\n + selectionRect.height\n // + window.scrollY\n - wrapperOffset.top\n + this.toolbarVerticalMargin,\n };\n /**\n * If we know selections width, place InlineToolbar to center\n */\n if (selectionRect.width) {\n newCoords.x += Math.floor(selectionRect.width / 2);\n }\n this.nodes.wrapper.style.left = Math.floor(newCoords.x) + 'px';\n this.nodes.wrapper.style.top = Math.floor(newCoords.y) + 'px';\n }\n /**\n * Shows Inline Toolbar\n */\n open() {\n this.nodes.wrapper.classList.add(this.CSS.inlineToolbarShowed);\n this.tools.forEach((tool) => {\n if (typeof tool.clear === 'function') {\n tool.clear();\n }\n });\n }\n /**\n * Hides Inline Toolbar\n */\n close() {\n this.nodes.wrapper.classList.remove(this.CSS.inlineToolbarShowed);\n this.tools.forEach((tool) => {\n if (typeof tool.clear === 'function') {\n tool.clear();\n }\n });\n }\n /**\n * Need to show Inline Toolbar or not\n * @param {KeyboardEvent|MouseEvent} event\n */\n allowedToShow(event) {\n /**\n * Tags conflicts with window.selection function.\n * Ex. IMG tag returns null (Firefox) or Redactors wrapper (Chrome)\n */\n const tagsConflictsWithSelection = ['IMG', 'INPUT'];\n if (event && tagsConflictsWithSelection.includes(event.target.tagName)) {\n return false;\n }\n const currentSelection = Selection.get(), selectedText = Selection.text;\n // old browsers\n if (!currentSelection || !currentSelection.anchorNode) {\n return false;\n }\n // empty selection\n if (currentSelection.isCollapsed || selectedText.length < 1) {\n return false;\n }\n // is enabled by current Block's Tool\n const currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode);\n if (!currentBlock) {\n return false;\n }\n const toolConfig = this.config.toolsConfig[currentBlock.name];\n return toolConfig && toolConfig[this.Editor.Tools.apiSettings.IS_ENABLED_INLINE_TOOLBAR];\n }\n /**\n *\n *\n * Working with Tools\n * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n *\n */\n /**\n * Fill Inline Toolbar with Tools\n */\n addTools() {\n this.tools.forEach((tool) => {\n this.addTool(tool);\n });\n }\n /**\n * Add tool button and activate clicks\n * @param {InlineTool} tool - Tool's instance\n */\n addTool(tool) {\n const button = tool.render();\n if (!button) {\n _.log('Render method must return an instance of Node', 'warn', tool);\n return;\n }\n this.nodes.buttons.appendChild(button);\n if (typeof tool.renderActions === 'function') {\n const actions = tool.renderActions();\n this.nodes.actions.appendChild(actions);\n }\n this.Editor.Listeners.on(button, 'click', () => {\n this.toolClicked(tool);\n });\n }\n /**\n * Inline Tool button clicks\n * @param {InlineTool} tool - Tool's instance\n */\n toolClicked(tool) {\n const range = Selection.range;\n tool.surround(range);\n this.checkToolsState();\n }\n /**\n * Check Tools` state by selection\n */\n checkToolsState() {\n this.tools.forEach((tool) => {\n tool.checkState(Selection.get());\n });\n }\n}\n","/**\n * @class Toolbox\n * @classdesc Holder for Tools\n *\n * @typedef {Toolbox} Toolbox\n * @property {Boolean} opened - opening state\n * @property {Object} nodes - Toolbox nodes\n * @property {Object} CSS - CSS class names\n *\n */\nexport default class Toolbox extends Module {\n /**\n * @constructor\n */\n constructor({config}) {\n super({config});\n\n this.nodes = {\n toolbox: null,\n buttons: []\n };\n\n /**\n * Opening state\n * @type {boolean}\n */\n this.opened = false;\n }\n\n /**\n * CSS styles\n * @return {{toolbox: string, toolboxButton: string, toolboxOpened: string}}\n */\n static get CSS() {\n return {\n toolbox: 'ce-toolbox',\n toolboxButton: 'ce-toolbox__button',\n toolboxOpened: 'ce-toolbox--opened',\n };\n }\n\n /**\n * Makes the Toolbox\n */\n make() {\n this.nodes.toolbox = $.make('div', Toolbox.CSS.toolbox);\n $.append(this.Editor.Toolbar.nodes.content, this.nodes.toolbox);\n\n this.addTools();\n }\n\n /**\n * Iterates available tools and appends them to the Toolbox\n */\n addTools() {\n let tools = this.Editor.Tools.toolsAvailable;\n\n for (let toolName in tools) {\n this.addTool(toolName, tools[toolName]);\n }\n }\n\n /**\n * Append Tool to the Toolbox\n *\n * @param {string} toolName - tool name\n * @param {Tool} tool - tool class\n */\n addTool(toolName, tool) {\n const api = this.Editor.Tools.apiSettings;\n\n if (tool[api.IS_DISPLAYED_IN_TOOLBOX] && !tool[api.TOOLBAR_ICON_CLASS]) {\n _.log('Toolbar icon class name is missed. Tool %o skipped', 'warn', toolName);\n return;\n }\n\n /**\n * @todo Add checkup for the render method\n */\n // if (typeof tool.render !== 'function') {\n //\n // _.log('render method missed. Tool %o skipped', 'warn', tool);\n // return;\n //\n // }\n\n /**\n * Skip tools that pass 'displayInToolbox=false'\n */\n if (!tool[api.IS_DISPLAYED_IN_TOOLBOX]) {\n return;\n }\n\n let button = $.make('li', [Toolbox.CSS.toolboxButton, tool[api.TOOLBAR_ICON_CLASS]], {\n title: toolName\n });\n\n /**\n * Save tool's name in the button data-name\n */\n button.dataset.name = toolName;\n\n $.append(this.nodes.toolbox, button);\n\n this.nodes.toolbox.appendChild(button);\n this.nodes.buttons.push(button);\n\n /**\n * @todo add event with module Listeners\n */\n // this.Editor.Listeners.add();\n button.addEventListener('click', event => {\n this.buttonClicked(event);\n }, false);\n }\n\n /**\n * Toolbox button click listener\n * 1) if block is empty -> replace\n * 2) if block is not empty -> add new block below\n *\n * @param {MouseEvent} event\n */\n buttonClicked(event) {\n let toolButton = event.target,\n toolName = toolButton.dataset.name,\n tool = this.Editor.Tools.toolClasses[toolName];\n\n /**\n * @type {Block}\n */\n let currentBlock = this.Editor.BlockManager.currentBlock;\n\n /**\n * We do replace if:\n * - block is empty\n * - block is not irreplaceable\n * @type {Array}\n */\n if (!tool[this.Editor.Tools.apiSettings.IS_IRREPLACEBLE_TOOL] && currentBlock.isEmpty) {\n this.Editor.BlockManager.replace(toolName);\n } else {\n this.Editor.BlockManager.insert(toolName);\n }\n\n /**\n * @todo set caret to the new block\n */\n\n // window.setTimeout(function () {\n\n /** Set caret to current block */\n // editor.caret.setToBlock(currentInputIndex);\n\n // }, 10);\n\n /**\n * Move toolbar when node is changed\n */\n this.Editor.Toolbar.move();\n }\n\n /**\n * Open Toolbox with Tools\n */\n open() {\n this.nodes.toolbox.classList.add(Toolbox.CSS.toolboxOpened);\n this.opened = true;\n }\n\n /**\n * Close Toolbox\n */\n close() {\n this.nodes.toolbox.classList.remove(Toolbox.CSS.toolboxOpened);\n this.opened = false;\n }\n\n /**\n * Close Toolbox\n */\n toggle() {\n if (!this.opened) {\n this.open();\n } else {\n this.close();\n }\n }\n}\n","/**\n *\n * «Toolbar» is the node that moves up/down over current block\n *\n * ______________________________________ Toolbar ____________________________________________\n * | |\n * | ..................... Content .................... ......... Block Actions .......... |\n * | . . . . |\n * | . . . [Open Settings] . |\n * | . [Plus Button] [Toolbox: {Tool1}, {Tool2}] . . . |\n * | . . . [Settings Panel] . |\n * | .................................................. .................................. |\n * | |\n * |___________________________________________________________________________________________|\n *\n *\n * Toolbox — its an Element contains tools buttons. Can be shown by Plus Button.\n *\n * _______________ Toolbox _______________\n * | |\n * | [Header] [Image] [List] [Quote] ... |\n * |_______________________________________|\n *\n *\n * Settings Panel — is an Element with block settings:\n *\n * ____ Settings Panel ____\n * | ...................... |\n * | . Tool Settings . |\n * | ...................... |\n * | . Default Settings . |\n * | ...................... |\n * |________________________|\n *\n *\n * @class\n * @classdesc Toolbar module\n *\n * @typedef {Toolbar} Toolbar\n * @property {Object} nodes\n * @property {Element} nodes.wrapper - Toolbar main element\n * @property {Element} nodes.content - Zone with Plus button and toolbox.\n * @property {Element} nodes.actions - Zone with Block Settings and Remove Button\n * @property {Element} nodes.blockActionsButtons - Zone with Block Buttons: [Settings]\n * @property {Element} nodes.plusButton - Button that opens or closes Toolbox\n * @property {Element} nodes.toolbox - Container for tools\n * @property {Element} nodes.settingsToggler - open/close Settings Panel button\n * @property {Element} nodes.settings - Settings Panel\n * @property {Element} nodes.pluginSettings - Plugin Settings section of Settings Panel\n * @property {Element} nodes.defaultSettings - Default Settings section of Settings Panel\n */\nexport default class Toolbar extends Module {\n /**\n * @constructor\n */\n constructor({config}) {\n super({config});\n\n this.nodes = {\n wrapper : null,\n content : null,\n actions : null,\n\n // Content Zone\n plusButton : null,\n\n // Actions Zone\n blockActionsButtons: null,\n settingsToggler : null,\n };\n }\n\n /**\n * CSS styles\n * @return {Object}\n * @constructor\n */\n static get CSS() {\n return {\n toolbar: 'ce-toolbar',\n content: 'ce-toolbar__content',\n actions: 'ce-toolbar__actions',\n\n toolbarOpened: 'ce-toolbar--opened',\n\n // Content Zone\n plusButton: 'ce-toolbar__plus',\n plusButtonHidden: 'ce-toolbar__plus--hidden',\n\n // Actions Zone\n blockActionsButtons: 'ce-toolbar__actions-buttons',\n settingsToggler: 'ce-toolbar__settings-btn',\n };\n }\n\n /**\n * Makes toolbar\n */\n make() {\n this.nodes.wrapper = $.make('div', Toolbar.CSS.toolbar);\n\n /**\n * Make Content Zone and Actions Zone\n */\n ['content', 'actions'].forEach( el => {\n this.nodes[el] = $.make('div', Toolbar.CSS[el]);\n $.append(this.nodes.wrapper, this.nodes[el]);\n });\n\n\n /**\n * Fill Content Zone:\n * - Plus Button\n * - Toolbox\n */\n this.nodes.plusButton = $.make('div', Toolbar.CSS.plusButton);\n $.append(this.nodes.plusButton, $.svg('plus', 14, 14));\n $.append(this.nodes.content, this.nodes.plusButton);\n this.nodes.plusButton.addEventListener('click', event => this.plusButtonClicked(event), false);\n\n\n /**\n * Make a Toolbox\n */\n this.Editor.Toolbox.make();\n\n /**\n * Fill Actions Zone:\n * - Settings Toggler\n * - Remove Block Button\n * - Settings Panel\n */\n this.nodes.blockActionsButtons = $.make('div', Toolbar.CSS.blockActionsButtons);\n this.nodes.settingsToggler = $.make('span', Toolbar.CSS.settingsToggler);\n const settingsIcon = $.svg('dots', 18, 4);\n\n $.append(this.nodes.settingsToggler, settingsIcon);\n $.append(this.nodes.blockActionsButtons, this.nodes.settingsToggler);\n $.append(this.nodes.actions, this.nodes.blockActionsButtons);\n\n /**\n * Make and append Settings Panel\n */\n this.Editor.BlockSettings.make();\n $.append(this.nodes.actions, this.Editor.BlockSettings.nodes.wrapper);\n\n /**\n * Append toolbar to the Editor\n */\n $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);\n\n /**\n * Bind events on the Toolbar elements\n */\n this.bindEvents();\n }\n\n /**\n * Move Toolbar to the Current Block\n * @param {Boolean} forceClose - force close Toolbar Settings and Toolbar\n */\n move(forceClose = true) {\n if (forceClose) {\n /** Close Toolbox when we move toolbar */\n this.Editor.Toolbox.close();\n this.Editor.BlockSettings.close();\n }\n\n let currentNode = this.Editor.BlockManager.currentNode;\n\n /**\n * If no one Block selected as a Current\n */\n if (!currentNode) {\n return;\n }\n\n /**\n * @todo Compute dynamically on prepare\n * @type {number}\n */\n const defaultToolbarHeight = 49;\n const defaultOffset = 34;\n\n var newYCoordinate = currentNode.offsetTop - (defaultToolbarHeight / 2) + defaultOffset;\n\n this.nodes.wrapper.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;\n }\n\n /**\n * Open Toolbar with Plus Button\n */\n open() {\n this.nodes.wrapper.classList.add(Toolbar.CSS.toolbarOpened);\n }\n\n /**\n * Close the Toolbar\n */\n close() {\n this.nodes.wrapper.classList.remove(Toolbar.CSS.toolbarOpened);\n }\n\n /**\n * Plus Button public methods\n * @return {{hide: function(): void, show: function(): void}}\n */\n get plusButton() {\n return {\n hide: () => this.nodes.plusButton.classList.add(Toolbar.CSS.plusButtonHidden),\n show: () => this.nodes.plusButton.classList.remove(Toolbar.CSS.plusButtonHidden)\n };\n }\n\n /**\n * Handler for Plus Button\n * @param {MouseEvent} event\n */\n plusButtonClicked() {\n this.Editor.Toolbox.toggle();\n }\n\n /**\n * Bind events on the Toolbar Elements:\n * - Block Settings\n */\n bindEvents() {\n /**\n * Settings toggler\n */\n this.Editor.Listeners.on(this.nodes.settingsToggler, 'click', (event) => {\n this.settingsTogglerClicked(event);\n });\n }\n\n /**\n * Clicks on the Block Settings toggler\n */\n settingsTogglerClicked() {\n if (this.Editor.BlockSettings.opened) {\n this.Editor.BlockSettings.close();\n } else {\n this.Editor.BlockSettings.open();\n }\n }\n}\n","/**\n * @module Codex Editor Tools Submodule\n *\n * Creates Instances from Plugins and binds external config to the instances\n */\n\n/**\n * Each Tool must contain the following important objects:\n *\n * @typedef {Object} ToolConfig {@link docs/tools.md}\n * @property {String} iconClassname - this a icon in toolbar\n * @property {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\n * @property {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\n * @property {Boolean|String[]} inlineToolbar - Pass `true` to enable the Inline Toolbar with all Tools, all pass an array with specified Tools list |\n * @property render @todo add description\n * @property save @todo add description\n * @property settings @todo add description\n * @property validate - method that validates output data before saving\n */\n\n/**\n * @typedef {Function} Tool {@link docs/tools.md}\n * @property {Boolean} displayInToolbox - By default, tools won't be added in the Toolbox. Pass true to add.\n * @property {String} iconClassName - CSS class name for the Toolbox button\n * @property {Boolean} irreplaceable - Toolbox behaviour: replace or add new block below\n * @property render\n * @property save\n * @property settings\n * @property validate\n *\n * @todo update according to current API\n * @todo describe Tool in the {@link docs/tools.md}\n */\n\n/**\n * Class properties:\n *\n * @typedef {Tools} Tools\n * @property {Tools[]} toolsAvailable - available Tools\n * @property {Tools[]} toolsUnavailable - unavailable Tools\n * @property {Object} toolsClasses - all classes\n * @property {EditorConfig} config - Editor config\n */\nexport default class Tools extends Module {\n /**\n * Returns available Tools\n * @return {Tool[]}\n */\n get available() {\n return this.toolsAvailable;\n }\n\n /**\n * Returns unavailable Tools\n * @return {Tool[]}\n */\n get unavailable() {\n return this.toolsUnavailable;\n }\n\n /**\n * Return Tools for the Inline Toolbar\n * @return {Array} - array of Inline Tool's classes\n */\n get inline() {\n return Object.values(this.available).filter( tool => {\n if (!tool[this.apiSettings.IS_INLINE]) {\n return false;\n }\n\n /**\n * Some Tools validation\n */\n const inlineToolRequiredMethods = ['render', 'surround', 'checkState'];\n const notImplementedMethods = inlineToolRequiredMethods.filter( method => !new tool()[method] );\n\n if (notImplementedMethods.length) {\n _.log(`Incorrect Inline Tool: ${tool.name}. Some of required methods is not implemented %o`, 'warn', notImplementedMethods);\n return false;\n }\n\n return true;\n });\n }\n\n /**\n * Constant for available Tools Settings\n * @return {object}\n */\n get apiSettings() {\n return {\n IS_INLINE: 'isInline',\n TOOLBAR_ICON_CLASS: 'iconClassName',\n IS_DISPLAYED_IN_TOOLBOX: 'displayInToolbox',\n IS_ENABLED_LINE_BREAKS: 'enableLineBreaks',\n IS_IRREPLACEBLE_TOOL: 'irreplaceable',\n IS_ENABLED_INLINE_TOOLBAR: 'inlineToolbar',\n };\n }\n\n /**\n * Static getter for default Tool config fields\n * @return {ToolConfig}\n */\n get defaultConfig() {\n return {\n [this.apiSettings.TOOLBAR_ICON_CLASS] : false,\n [this.apiSettings.IS_DISPLAYED_IN_TOOLBOX] : false,\n [this.apiSettings.IS_ENABLED_LINE_BREAKS] : false,\n [this.apiSettings.IS_IRREPLACEBLE_TOOL] : false,\n [this.apiSettings.IS_ENABLED_INLINE_TOOLBAR]: false,\n };\n }\n\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor({config}) {\n super({config});\n\n /**\n * Map {name: Class, ...} where:\n * name — block type name in JSON. Got from EditorConfig.tools keys\n * @type {Object}\n */\n this.toolClasses = {};\n\n /**\n * Available tools list\n * {name: Class, ...}\n * @type {Object}\n */\n this.toolsAvailable = {};\n\n /**\n * Tools that rejected a prepare method\n * {name: Class, ... }\n * @type {Object}\n */\n this.toolsUnavailable = {};\n }\n\n /**\n * Creates instances via passed or default configuration\n * @return {Promise}\n */\n prepare() {\n if (!this.config.hasOwnProperty('tools')) {\n return Promise.reject(\"Can't start without tools\");\n }\n\n for(let toolName in this.config.tools) {\n this.toolClasses[toolName] = this.config.tools[toolName];\n }\n\n /**\n * getting classes that has prepare method\n */\n let sequenceData = this.getListOfPrepareFunctions();\n\n /**\n * if sequence data contains nothing then resolve current chain and run other module prepare\n */\n if (sequenceData.length === 0) {\n return Promise.resolve();\n }\n\n /**\n * to see how it works {@link Util#sequence}\n */\n return _.sequence(sequenceData, (data) => {\n this.success(data);\n }, (data) => {\n this.fallback(data);\n });\n }\n\n /**\n * Binds prepare function of plugins with user or default config\n * @return {Array} list of functions that needs to be fired sequentially\n */\n getListOfPrepareFunctions() {\n let toolPreparationList = [];\n\n for(let toolName in this.toolClasses) {\n let toolClass = this.toolClasses[toolName];\n\n if (typeof toolClass.prepare === 'function') {\n toolPreparationList.push({\n function : toolClass.prepare,\n data : {\n toolName\n }\n });\n } else {\n /**\n * If Tool hasn't a prepare method, mark it as available\n */\n this.toolsAvailable[toolName] = toolClass;\n }\n }\n\n return toolPreparationList;\n }\n\n /**\n * @param {ChainData.data} data - append tool to available list\n */\n success(data) {\n this.toolsAvailable[data.toolName] = this.toolClasses[data.toolName];\n }\n\n /**\n * @param {ChainData.data} data - append tool to unavailable list\n */\n fallback(data) {\n this.toolsUnavailable[data.toolName] = this.toolClasses[data.toolName];\n }\n\n /**\n * Return tool`a instance\n *\n * @param {String} tool — tool name\n * @param {Object} data — initial data\n *\n * @todo throw exceptions if tool doesnt exist\n *\n */\n construct(tool, data) {\n let plugin = this.toolClasses[tool],\n config = this.config.toolsConfig[tool];\n\n let instance = new plugin(data, config || {});\n\n return instance;\n }\n\n /**\n * Check if passed Tool is an instance of Initial Block Tool\n * @param {Tool} tool - Tool to check\n * @return {Boolean}\n */\n isInitial(tool) {\n return tool instanceof this.available[this.config.initialBlock];\n }\n}\n","/**\n * Module UI\n *\n * @type {UI}\n */\n\n/**\n * Prebuilded sprite of SVG icons\n */\nimport sprite from '../../../build/sprite.svg';\n\n/**\n * @class\n *\n * @classdesc Makes CodeX Editor UI:\n * \n * \n * \n * \n * \n *\n * @typedef {UI} UI\n * @property {EditorConfig} config - editor configuration {@link CodexEditor#configuration}\n * @property {Object} Editor - available editor modules {@link CodexEditor#moduleInstances}\n * @property {Object} nodes -\n * @property {Element} nodes.holder - element where we need to append redactor\n * @property {Element} nodes.wrapper - \n * @property {Element} nodes.redactor - \n */\nexport default class UI extends Module {\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor({config}) {\n super({config});\n\n this.nodes = {\n holder: null,\n wrapper: null,\n redactor: null\n };\n }\n\n /**\n * Making main interface\n */\n prepare() {\n return this.make()\n /**\n * Append SVG sprite\n */\n .then(() => this.appendSVGSprite())\n /**\n * Make toolbar\n */\n .then(() => this.Editor.Toolbar.make())\n /**\n * Make the Inline toolbar\n */\n .then(() => this.Editor.InlineToolbar.make())\n /**\n * Load and append CSS\n */\n .then(() => this.loadStyles())\n /**\n * Bind events for the UI elements\n */\n .then(() => this.bindEvents())\n\n /** Make container for inline toolbar */\n // .then(makeInlineToolbar_)\n\n /** Add inline toolbar tools */\n // .then(addInlineToolbarTools_)\n\n /** Draw wrapper for notifications */\n // .then(makeNotificationHolder_)\n\n /** Add eventlisteners to redactor elements */\n // .then(bindEvents_)\n\n .catch(e => {\n console.error(e);\n\n // editor.core.log(\"Can't draw editor interface\");\n });\n }\n\n /**\n * CodeX Editor UI CSS class names\n * @return {{editorWrapper: string, editorZone: string, block: string}}\n */\n get CSS() {\n return {\n editorWrapper : 'codex-editor',\n editorZone : 'codex-editor__redactor',\n };\n }\n\n /**\n * Makes CodeX Editor interface\n * @return {Promise}\n */\n make() {\n return new Promise( (resolve, reject) => {\n /**\n * Element where we need to append CodeX Editor\n * @type {Element}\n */\n this.nodes.holder = document.getElementById(this.config.holderId);\n\n if (!this.nodes.holder) {\n reject(Error(\"Holder wasn't found by ID: #\" + this.config.holderId));\n return;\n }\n\n /**\n * Create and save main UI elements\n */\n this.nodes.wrapper = $.make('div', this.CSS.editorWrapper);\n this.nodes.redactor = $.make('div', this.CSS.editorZone);\n\n this.nodes.wrapper.appendChild(this.nodes.redactor);\n this.nodes.holder.appendChild(this.nodes.wrapper);\n\n resolve();\n });\n }\n\n /**\n * Appends CSS\n */\n loadStyles() {\n /**\n * Load CSS\n */\n let styles = require('../../styles/main.css');\n\n /**\n * Make tag\n */\n let tag = $.make('style', null, {\n textContent: styles.toString()\n });\n\n /**\n * Append styles\n */\n $.append(document.head, tag);\n }\n\n /**\n * Bind events on the CodeX Editor interface\n */\n bindEvents() {\n this.Editor.Listeners.on(this.nodes.redactor, 'click', event => this.redactorClicked(event), false );\n this.Editor.Listeners.on(document, 'click', event => this.documentClicked(event), false );\n }\n\n /**\n * All clicks on document\n * @param {MouseEvent} event - Click\n */\n documentClicked(event) {\n /**\n * Close Inline Toolbar when nothing selected\n * Do not fire check on clicks at the Inline Toolbar buttons\n */\n const clickedOnInlineToolbarButton = event.target.closest(`.${this.Editor.InlineToolbar.CSS.inlineToolbar}`);\n\n if (!clickedOnInlineToolbarButton) {\n this.Editor.InlineToolbar.handleShowingEvent(event);\n }\n }\n\n /**\n * All clicks on the redactor zone\n *\n * @param {MouseEvent} event\n *\n * @description\n * 1. Save clicked Block as a current {@link BlockManager#currentNode}\n * it uses for the following:\n * - add CSS modifier for the selected Block\n * - on Enter press, we make a new Block under that\n *\n * 2. Move and show the Toolbar\n *\n * 3. Set a Caret\n *\n * 4. By clicks on the Editor's bottom zone:\n * - if last Block is empty, set a Caret to this\n * - otherwise, add a new empty Block and set a Caret to that\n *\n * 5. Hide the Inline Toolbar\n *\n * @see selectClickedBlock\n *\n */\n redactorClicked(event) {\n let clickedNode = event.target;\n\n /**\n * Select clicked Block as Current\n */\n try {\n this.Editor.BlockManager.setCurrentBlockByChildNode(clickedNode);\n } catch (e) {\n /**\n * If clicked outside first-level Blocks, set Caret to the last empty Block\n */\n this.Editor.Caret.setToTheLastBlock();\n }\n\n /**\n *\n\n /** Update current input index in memory when caret focused into existed input */\n // if (event.target.contentEditable == 'true') {\n //\n // editor.caret.saveCurrentInputIndex();\n //\n // }\n\n // if (editor.content.currentNode === null) {\n //\n // /**\n // * If inputs in redactor does not exits, then we put input index 0 not -1\n // */\n // var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0;\n //\n // /** If we have any inputs */\n // if (editor.state.inputs.length) {\n //\n // /** getting firstlevel parent of input */\n // firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);\n //\n // }\n //\n // /** If input is empty, then we set caret to the last input */\n // if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {\n //\n // editor.caret.setToBlock(indexOfLastInput);\n //\n // } else {\n //\n // /** Create new input when caret clicked in redactors area */\n // var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n //\n // editor.content.insertBlock({\n // type : NEW_BLOCK_TYPE,\n // block : editor.tools[NEW_BLOCK_TYPE].render()\n // });\n //\n // /** If there is no inputs except inserted */\n // if (editor.state.inputs.length === 1) {\n //\n // editor.caret.setToBlock(indexOfLastInput);\n //\n // } else {\n //\n // /** Set caret to this appended input */\n // editor.caret.setToNextBlock(indexOfLastInput);\n //\n // }\n //\n // }\n //\n // } else {\n //\n // /** Close all panels */\n // editor.toolbar.settings.close();\n // editor.toolbar.toolbox.close();\n //\n // }\n //\n /**\n * Move toolbar and open\n */\n this.Editor.Toolbar.move();\n this.Editor.Toolbar.open();\n //\n // var inputIsEmpty = !editor.content.currentNode.textContent.trim(),\n // currentNodeType = editor.content.currentNode.dataset.tool,\n // isInitialType = currentNodeType == editor.settings.initialBlockPlugin;\n //\n //\n\n /**\n * Hide the Plus Button\n * */\n this.Editor.Toolbar.plusButton.hide();\n\n /**\n * Show the Plus Button if:\n * - Block is an initial-block (Text)\n * - Block is empty\n */\n let isInitialBlock = this.Editor.Tools.isInitial(this.Editor.BlockManager.currentBlock.tool),\n isEmptyBlock = this.Editor.BlockManager.currentBlock.isEmpty;\n\n if (isInitialBlock && isEmptyBlock) {\n this.Editor.Toolbar.plusButton.show();\n }\n }\n\n /**\n * Append prebuilded sprite with SVG icons\n */\n appendSVGSprite() {\n let spriteHolder = $.make('div');\n\n spriteHolder.innerHTML = sprite;\n\n $.append(this.nodes.wrapper, spriteHolder);\n }\n}\n\n// /**\n// * Codex Editor UI module\n// *\n// * @author Codex Team\n// * @version 1.2.0\n// */\n//\n// module.exports = (function (ui) {\n//\n// let editor = codex.editor;\n//\n// /**\n// * Basic editor classnames\n// */\n// ui.prepare = function () {\n//\n\n//\n// };\n//\n// /** Draw notifications holder */\n// var makeNotificationHolder_ = function () {\n//\n// /** Append block with notifications to the document */\n// editor.nodes.notifications = editor.notifications.createHolder();\n//\n// };\n//\n//\n// var addInlineToolbarTools_ = function () {\n//\n// var tools = {\n//\n// bold: {\n// icon : 'ce-icon-bold',\n// command : 'bold'\n// },\n//\n// italic: {\n// icon : 'ce-icon-italic',\n// command : 'italic'\n// },\n//\n// link: {\n// icon : 'ce-icon-link',\n// command : 'createLink'\n// }\n// };\n//\n// var toolButton,\n// tool;\n//\n// for(var name in tools) {\n//\n// tool = tools[name];\n//\n// toolButton = editor.draw.toolbarButtonInline(name, tool.icon);\n//\n// editor.nodes.inlineToolbar.buttons.appendChild(toolButton);\n// /**\n// * Add callbacks to this buttons\n// */\n// editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);\n//\n// }\n//\n// };\n//\n// /**\n// * @private\n// * Bind editor UI events\n// */\n// var bindEvents_ = function () {\n//\n// editor.core.log('ui.bindEvents fired', 'info');\n//\n// // window.addEventListener('error', function (errorMsg, url, lineNumber) {\n// // editor.notifications.errorThrown(errorMsg, event);\n// // }, false );\n//\n// /** All keydowns on Document */\n// editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n//\n// /** All keydowns on Redactor zone */\n// editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n//\n// /** All keydowns on Document */\n// editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );\n//\n// /**\n// * Mouse click to radactor\n// */\n// editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );\n//\n// /**\n// * Clicks to the Plus button\n// */\n// editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n//\n// /**\n// * Clicks to SETTINGS button in toolbar\n// */\n// editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );\n//\n// /** Bind click listeners on toolbar buttons */\n// for (var button in editor.nodes.toolbarButtons) {\n//\n// editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n//\n// }\n//\n// };\n//\n// ui.addBlockHandlers = function (block) {\n//\n// if (!block) return;\n//\n// /**\n// * Block keydowns\n// */\n// editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n//\n// /**\n// * Pasting content from another source\n// * We have two type of sanitization\n// * First - uses deep-first search algorithm to get sub nodes,\n// * sanitizes whole Block_content and replaces cleared nodes\n// * This method is deprecated\n// * Method is used in editor.callback.blockPaste(event)\n// *\n// * Secont - uses Mutation observer.\n// * Observer \"observe\" DOM changes and send changings to callback.\n// * Callback gets changed node, not whole Block_content.\n// * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n// *\n// * Method is used in editor.callback.blockPasteViaSanitize(event)\n// *\n// * @uses html-janitor\n// * @example editor.callback.blockPasteViaSanitize(event), the second method.\n// *\n// */\n// editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);\n//\n// /**\n// * Show inline toolbar for selected text\n// */\n// editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\n// editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);\n//\n// };\n//\n// /** getting all contenteditable elements */\n// ui.saveInputs = function () {\n//\n// var redactor = editor.nodes.redactor;\n//\n// editor.state.inputs = [];\n//\n// /** Save all inputs in global variable state */\n// var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\n//\n// Array.prototype.map.call(inputs, function (current) {\n//\n// if (!current.type || current.type == 'text' || current.type == 'textarea') {\n//\n// editor.state.inputs.push(current);\n//\n// }\n//\n// });\n//\n// };\n//\n// /**\n// * Adds first initial block on empty redactor\n// */\n// ui.addInitialBlock = function () {\n//\n// var initialBlockType = editor.settings.initialBlockPlugin,\n// initialBlock;\n//\n// if ( !editor.tools[initialBlockType] ) {\n//\n// editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\n// return;\n//\n// }\n//\n// initialBlock = editor.tools[initialBlockType].render();\n//\n// initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);\n//\n// editor.content.insertBlock({\n// type : initialBlockType,\n// block : initialBlock\n// });\n//\n// editor.content.workingNodeChanged(initialBlock);\n//\n// };\n//\n// ui.setInlineToolbarButtonBehaviour = function (button, type) {\n//\n// editor.listeners.add(button, 'mousedown', function (event) {\n//\n// editor.toolbar.inline.toolClicked(event, type);\n//\n// }, false);\n//\n// };\n//\n// return ui;\n//\n// })({});\n","/**\n * Element.closest()\n *\n * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest\n */\nif (!Element.prototype.matches)\n Element.prototype.matches = Element.prototype.msMatchesSelector ||\n Element.prototype.webkitMatchesSelector;\n\nif (!Element.prototype.closest)\n Element.prototype.closest = function (s) {\n var el = this;\n\n if (!document.documentElement.contains(el)) return null;\n do {\n if (el.matches(s)) return el;\n el = el.parentElement || el.parentNode;\n } while (el !== null);\n return null;\n };\n","/**\n * Working with selection\n * @typedef {Selection} Selection\n */\nexport default class Selection {\n /**\n * @constructor\n */\n constructor() {\n this.instance = null;\n this.selection = null;\n\n /**\n * This property can store Selection's range for restoring later\n * @type {Range|null}\n */\n this.savedSelectionRange = null;\n }\n\n /**\n * Returns window Selection\n * {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}\n * @return {Selection}\n */\n static get() {\n return window.getSelection();\n }\n\n /**\n * Returns selected anchor\n * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorNode}\n * @return {Node|null}\n */\n static get anchorNode() {\n const selection = window.getSelection();\n\n return selection ? selection.anchorNode : null;\n }\n\n /**\n * Returns selection offset according to the anchor node\n * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorOffset}\n * @return {Number|null}\n */\n static get anchorOffset() {\n const selection = window.getSelection();\n\n return selection ? selection.anchorOffset : null;\n }\n\n /**\n * Is current selection range collapsed\n * @return {boolean|null}\n */\n static get isCollapsed() {\n const selection = window.getSelection();\n\n return selection ? selection.isCollapsed : null;\n }\n\n /**\n * Return first range\n * @return {Range|null}\n */\n static get range() {\n const selection = window.getSelection();\n\n return selection && selection.rangeCount ? selection.getRangeAt(0) : null;\n }\n\n /**\n * Calculates position and size of selected text\n * @return {{x, y, width, height, top?, left?, bottom?, right?}}\n */\n static get rect() {\n let sel = document.selection, range;\n let rect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0\n };\n\n if (sel && sel.type !== 'Control') {\n range = sel.createRange();\n rect.x = range.boundingLeft;\n rect.y = range.boundingTop;\n rect.width = range.boundingWidth;\n rect.height = range.boundingHeight;\n\n return rect;\n }\n\n if (!window.getSelection) {\n _.log('Method window.getSelection is not supported', 'warn');\n return rect;\n }\n\n sel = window.getSelection();\n\n if (!sel.rangeCount) {\n _.log('Method Selection.rangeCount() is not supported', 'warn');\n return rect;\n }\n\n range = sel.getRangeAt(0).cloneRange();\n\n if (range.getBoundingClientRect) {\n rect = range.getBoundingClientRect();\n }\n // Fall back to inserting a temporary element\n if (rect.x === 0 && rect.y === 0) {\n let span = document.createElement('span');\n\n if (span.getBoundingClientRect) {\n // Ensure span has dimensions and position by\n // adding a zero-width space character\n span.appendChild( document.createTextNode('\\u200b') );\n range.insertNode(span);\n rect = span.getBoundingClientRect();\n\n let spanParent = span.parentNode;\n\n spanParent.removeChild(span);\n\n // Glue any broken text nodes back together\n spanParent.normalize();\n }\n }\n\n return rect;\n }\n\n /**\n * Returns selected text as String\n * @returns {string}\n */\n static get text() {\n return window.getSelection ? window.getSelection().toString() : '';\n };\n\n /**\n * Save Selection's range\n */\n save() {\n this.savedSelectionRange = Selection.range;\n }\n\n /**\n * Restore saved Selection's range\n */\n restore() {\n if (!this.savedSelectionRange) {\n return;\n }\n\n const sel = window.getSelection();\n\n sel.removeAllRanges();\n sel.addRange(this.savedSelectionRange);\n }\n\n /**\n * Clears saved selection\n */\n clearSaved() {\n this.savedSelectionRange = null;\n }\n\n /**\n * Looks ahead to find passed tag from current selection\n *\n * @param {String} tagName - tag to found\n * @param {String} [className] - tag's class name\n * @param {Number} [searchDepth] - count of tags that can be included. For better performance.\n * @return {HTMLElement|null}\n */\n findParentTag(tagName, className, searchDepth = 10) {\n let selection = window.getSelection(),\n parentTag = null;\n\n /**\n * If selection is missing or no anchorNode or focusNode were found then return null\n */\n if (!selection || !selection.anchorNode || !selection.focusNode) {\n return null;\n }\n\n /**\n * Define Nodes for start and end of selection\n */\n let boundNodes = [\n /** the Node in which the selection begins */\n selection.anchorNode,\n /** the Node in which the selection ends */\n selection.focusNode\n ];\n\n /**\n * For each selection parent Nodes we try to find target tag [with target class name]\n * It would be saved in parentTag variable\n */\n boundNodes.forEach(parent => {\n /** Reset tags limit */\n let searchDepthIterable = searchDepth;\n\n while (searchDepthIterable > 0 && parent.parentNode) {\n /**\n * Check tag's name\n */\n if (parent.tagName === tagName) {\n /**\n * Optional additional check for class-name matching\n */\n if (className && parent.classList && !parent.classList.contains(className)) {\n continue;\n }\n\n /**\n * If we have found required tag with class then save the result and go out from cycle\n */\n parentTag = parent;\n break;\n }\n\n /**\n * Target tag was not found. Go up to the parent and check it\n */\n parent = parent.parentNode;\n searchDepthIterable--;\n }\n });\n\n /**\n * Return found tag or null\n */\n return parentTag;\n }\n\n /**\n * Expands selection range to the passed parent node\n *\n * @param {HTMLElement} node\n */\n expandToTag(node) {\n let selection = window.getSelection();\n\n selection.removeAllRanges();\n let range = document.createRange();\n\n range.selectNodeContents(node);\n selection.addRange(range);\n }\n}\n","/**\n * Codex Editor Util\n */\nexport default class Util {\n /**\n * Custom logger\n *\n * @param {string} msg - message\n * @param {string} type - logging type 'log'|'warn'|'error'|'info'\n * @param {*} args - argument to log with a message\n */\n static log(msg, type, args) {\n type = type || 'log';\n\n if (!args) {\n args = msg || 'undefined';\n msg = '[codex-editor]: %o';\n } else {\n msg = '[codex-editor]: ' + msg;\n }\n\n try{\n if ( 'console' in window && window.console[ type ] ) {\n if ( args ) window.console[ type ]( msg, args );\n else window.console[ type ]( msg );\n }\n } catch(e) {\n // do nothing\n }\n }\n\n /**\n * Returns basic keycodes as constants\n * @return {{}}\n */\n static get keyCodes() {\n return {\n BACKSPACE: 8,\n TAB: 9,\n ENTER: 13,\n SHIFT: 16,\n CTRL: 17,\n ALT: 18,\n ESC: 27,\n SPACE: 32,\n LEFT: 37,\n UP: 38,\n DOWN: 40,\n RIGHT: 39,\n DELETE: 46,\n META: 91\n };\n }\n\n /**\n * @typedef {Object} ChainData\n * @property {Object} data - data that will be passed to the success or fallback\n * @property {Function} function - function's that must be called asynchronically\n */\n\n /**\n * Fires a promise sequence asyncronically\n *\n * @param {Object[]} chains - list or ChainData's\n * @param {Function} success - success callback\n * @param {Function} fallback - callback that fires in case of errors\n *\n * @return {Promise}\n */\n static sequence(chains, success = () => {}, fallback = () => {}) {\n return new Promise(function (resolve) {\n /**\n * pluck each element from queue\n * First, send resolved Promise as previous value\n * Each plugins \"prepare\" method returns a Promise, that's why\n * reduce current element will not be able to continue while can't get\n * a resolved Promise\n */\n chains.reduce(function (previousValue, currentValue, iteration) {\n return previousValue\n .then(() => waitNextBlock(currentValue, success, fallback))\n .then(() => {\n // finished\n if (iteration === chains.length - 1) {\n resolve();\n }\n });\n }, Promise.resolve());\n });\n\n /**\n * Decorator\n *\n * @param {ChainData} chainData\n *\n * @param {Function} successCallback\n * @param {Function} fallbackCallback\n *\n * @return {Promise}\n */\n function waitNextBlock(chainData, successCallback, fallbackCallback) {\n return new Promise(function (resolve) {\n chainData.function()\n .then(() => {\n successCallback(chainData.data || {});\n })\n .then(resolve)\n .catch(function () {\n fallbackCallback(chainData.data || {});\n\n // anyway, go ahead even it falls\n resolve();\n });\n });\n }\n }\n\n /**\n * Make array from array-like collection\n *\n * @param {*} collection\n *\n * @return {Array}\n */\n static array(collection) {\n return Array.prototype.slice.call(collection);\n }\n\n /**\n * Checks if object is empty\n *\n * @param {Object} object\n * @return {boolean}\n */\n static isEmpty(object) {\n return Object.keys(object).length === 0 && object.constructor === Object;\n }\n\n /**\n * Check if passed object is a Promise\n * @param {*} object - object to check\n * @return {Boolean}\n */\n static isPromise(object) {\n return Promise.resolve(object) === object;\n }\n\n /**\n * Check if passed element is contenteditable\n * @param element\n * @return {boolean}\n */\n static isContentEditable(element) {\n return element.contentEditable === 'true';\n }\n\n /**\n * Delays method execution\n *\n * @param method\n * @param timeout\n */\n static delay(method, timeout) {\n return function () {\n let context = this,\n args = arguments;\n\n window.setTimeout(() => method.apply(context, args), timeout);\n };\n }\n};\n","exports = module.exports = require(\"../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \":root {\\n /**\\n * Toolbar buttons\\n */\\n --bg-light: #eff2f5;\\n\\n /**\\n * All gray texts: placeholders, settings\\n */\\n --grayText: #707684;\\n\\n /** Blue icons */\\n --color-active-icon: #388AE5;\\n\\n /**\\n * Block content width\\n */\\n --content-width: 650px;\\n\\n /**\\n * Toolbar Plus Button and Toolbox buttons height and width\\n */\\n --toolbar-buttons-size: 34px;\\n\\n /**\\n * Confirm deletion bg\\n */\\n --color-confirm: #E24A4A;\\n}\\n/**\\n* Editor wrapper\\n*/\\n.codex-editor {\\n position: relative;\\n box-sizing: border-box;\\n\\n\\n}\\n.codex-editor .hide {\\n display: none;\\n }\\n.codex-editor__redactor {\\n padding-bottom: 300px;\\n }\\n.codex-editor svg {\\n fill: currentColor;\\n vertical-align: middle;\\n max-height: 100%;\\n }\\n::-moz-selection{\\n background-color: rgba(61,166,239,0.63);\\n}\\n::selection{\\n background-color: rgba(61,166,239,0.63);\\n}\\n.ce-tune-moveup{}\\n.ce-settings-delete:hover {\\n cursor: pointer;\\n }\\n.ce-settings-delete::before {\\n content: 'delete'\\n }\\n.ce-toolbar {\\n position: absolute;\\n left: 0;\\n right: 0;\\n top: 0;\\n /*opacity: 0;*/\\n /*visibility: hidden;*/\\n transition: opacity 100ms ease;\\n will-change: opacity, transform;\\n display: none;\\n}\\n.ce-toolbar--opened {\\n display: block;\\n /*opacity: 1;*/\\n /*visibility: visible;*/\\n }\\n.ce-toolbar__content {\\n max-width: 650px;\\n max-width: var(--content-width);\\n margin: 0 auto;\\n position: relative;\\n }\\n.ce-toolbar__plus {\\n position: absolute;\\n left: calc(calc(34px + 10px) * -1);\\n left: calc(calc(var(--toolbar-buttons-size) + 10px) * -1);\\n display: inline-block;\\n background-color: #eff2f5;\\n background-color: var(--bg-light);\\n width: 34px;\\n width: var(--toolbar-buttons-size);\\n height: 34px;\\n height: var(--toolbar-buttons-size);\\n line-height: 34px;\\n text-align: center;\\n border-radius: 50%;\\n cursor: pointer;\\n }\\n.ce-toolbar__plus--hidden {\\n display: none;\\n }\\n/**\\n * Block actions Zone\\n * -------------------------\\n */\\n.ce-toolbar__actions {\\n position: absolute;\\n right: 0;\\n top: 0;\\n padding-right: 16px;\\n }\\n.ce-toolbar__actions-buttons {\\n text-align: right;\\n }\\n.ce-toolbar__settings-btn {\\n display: inline-block;\\n width: 24px;\\n height: 24px;\\n color: #707684;\\n color: var(--grayText);\\n cursor: pointer;\\n }\\n.ce-toolbox {\\n position: absolute;\\n visibility: hidden;\\n transition: opacity 100ms ease;\\n will-change: opacity;\\n}\\n.ce-toolbox--opened {\\n opacity: 1;\\n visibility: visible;\\n }\\n.ce-toolbox__button {\\n display: inline-block;\\n list-style: none;\\n margin: 0;\\n background: #eff2f5;\\n background: var(--bg-light);\\n width: 34px;\\n width: var(--toolbar-buttons-size);\\n height: 34px;\\n height: var(--toolbar-buttons-size);\\n border-radius: 30px;\\n overflow: hidden;\\n text-align: center;\\n line-height: 34px;\\n line-height: var(--toolbar-buttons-size)\\n }\\n.ce-toolbox__button::before {\\n content: attr(title);\\n font-size: 22px;\\n font-weight: 500;\\n letter-spacing: 1em;\\n -webkit-font-feature-settings: \\\"smcp\\\", \\\"c2sc\\\";\\n font-feature-settings: \\\"smcp\\\", \\\"c2sc\\\";\\n font-variant-caps: all-small-caps;\\n padding-left: 11.5px;\\n margin-top: -1px;\\n display: inline-block;\\n }\\n.ce-inline-toolbar {\\n position: absolute;\\n background-color: #FFFFFF;\\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\\n border-radius: 4px;\\n z-index: 2\\n}\\n.ce-inline-toolbar::before {\\n content: '';\\n width: 15px;\\n height: 15px;\\n position: absolute;\\n top: -7px;\\n left: 50%;\\n margin-left: -7px;\\n transform: rotate(-45deg);\\n background-color: #fff;\\n z-index: -1;\\n }\\n.ce-inline-toolbar {\\n padding: 6px;\\n transform: translateX(-50%);\\n display: none;\\n box-shadow: 0 6px 12px -6px rgba(131, 147, 173, 0.46),\\n 5px -12px 34px -13px rgba(97, 105, 134, 0.6),\\n 0 26px 52px 3px rgba(147, 165, 186, 0.24);\\n}\\n.ce-inline-toolbar--showed {\\n display: block;\\n }\\n.ce-inline-tool {\\n display: inline-block;\\n width: 34px;\\n height: 34px;\\n line-height: 34px;\\n text-align: center;\\n border-radius: 3px;\\n cursor: pointer;\\n border: 0;\\n outline: none;\\n background-color: transparent;\\n vertical-align: bottom;\\n color: #707684;\\n color: var(--grayText)\\n}\\n.ce-inline-tool:not(:last-of-type){\\n margin-right: 5px;\\n }\\n.ce-inline-tool:hover {\\n background-color: #eff2f5;\\n background-color: var(--bg-light);\\n }\\n.ce-inline-tool {\\n line-height: normal;\\n}\\n.ce-inline-tool--active {\\n color: #388AE5;\\n color: var(--color-active-icon);\\n }\\n.ce-inline-tool--link .icon {\\n margin-top: -2px;\\n }\\n.ce-inline-tool--link .icon--unlink {\\n display: none;\\n }\\n.ce-inline-tool--unlink .icon--link {\\n display: none;\\n }\\n.ce-inline-tool--unlink .icon--unlink {\\n display: inline-block;\\n }\\n.ce-inline-tool-input {\\n background-color: #eff2f5;\\n background-color: var(--bg-light);\\n outline: none;\\n border: 0;\\n border-radius: 3px;\\n margin: 6px 0 0;\\n font-size: 13px;\\n padding: 8px;\\n width: 100%;\\n box-sizing: border-box;\\n display: none\\n }\\n.ce-inline-tool-input::-webkit-input-placeholder {\\n color: #707684;\\n color: var(--grayText);\\n }\\n.ce-inline-tool-input:-ms-input-placeholder {\\n color: #707684;\\n color: var(--grayText);\\n }\\n.ce-inline-tool-input::placeholder {\\n color: #707684;\\n color: var(--grayText);\\n }\\n.ce-inline-tool-input--showed {\\n display: block;\\n }\\n.ce-settings {\\n position: absolute;\\n background-color: #FFFFFF;\\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\\n border-radius: 4px;\\n z-index: 2\\n}\\n.ce-settings::before {\\n content: '';\\n width: 15px;\\n height: 15px;\\n position: absolute;\\n top: -7px;\\n left: 50%;\\n margin-left: -7px;\\n transform: rotate(-45deg);\\n background-color: #fff;\\n z-index: -1;\\n }\\n.ce-settings {\\n right: 5px;\\n top: 35px;\\n min-width: 124px\\n}\\n.ce-settings::before{\\n left: auto;\\n right: 12px;\\n }\\n.ce-settings {\\n\\n display: none;\\n}\\n.ce-settings--opened {\\n display: block;\\n }\\n.ce-settings__plugin-zone:not(:empty){\\n padding: 6px;\\n }\\n.ce-settings__default-zone:not(:empty){\\n padding: 6px;\\n }\\n.ce-settings__button {\\n display: inline-block;\\n width: 34px;\\n height: 34px;\\n line-height: 34px;\\n text-align: center;\\n border-radius: 3px;\\n cursor: pointer;\\n border: 0;\\n outline: none;\\n background-color: transparent;\\n vertical-align: bottom;\\n color: #707684;\\n color: var(--grayText)\\n }\\n.ce-settings__button:not(:last-of-type){\\n margin-right: 5px;\\n }\\n.ce-settings__button:hover {\\n background-color: #eff2f5;\\n background-color: var(--bg-light);\\n }\\n.ce-settings__button--active {\\n color: #388AE5;\\n color: var(--color-active-icon);\\n }\\n.ce-settings__button--delete {\\n transition: background-color 300ms ease;\\n will-change: background-color;\\n }\\n.ce-settings__button--delete .icon {\\n transition: transform 200ms ease-out;\\n will-change: transform;\\n }\\n.ce-settings__button--confirm {\\n background-color: #E24A4A;\\n background-color: var(--color-confirm);\\n color: #fff\\n }\\n.ce-settings__button--confirm:hover {\\n background-color: rgb(213, 74, 74) !important;\\n background-color: rgb(213, 74, 74) !important;\\n }\\n.ce-settings__button--confirm .icon {\\n transform: rotate(90deg);\\n }\\n.ce-settings-move-up:hover {\\n cursor: pointer;\\n }\\n.ce-settings-move-up--disabled {\\n cursor: not-allowed !important;\\n opacity: .3;\\n }\\n.ce-block:first-of-type {\\n margin-top: 0;\\n }\\n.ce-block--selected {\\n background-image: linear-gradient(17deg, rgba(243, 248, 255, 0.03) 63.45%, rgba(207, 214, 229, 0.27) 98%);\\n border-radius: 3px;\\n }\\n.ce-block__content {\\n max-width: 650px;\\n max-width: var(--content-width);\\n margin: 0 auto;\\n }\\n\", \"\"]);\n\n// exports\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://CodexEditor/webpack/universalModuleDefinition","webpack://CodexEditor/webpack/bootstrap","webpack://CodexEditor/./build/sprite.svg","webpack://CodexEditor/./node_modules/css-loader/lib/css-base.js","webpack://CodexEditor/./node_modules/html-janitor/src/html-janitor.js","webpack://CodexEditor/./src/codex.js","webpack://CodexEditor/./src/components/__module.ts","webpack://CodexEditor/./src/components/block-tunes/block-tune-delete.ts","webpack://CodexEditor/./src/components/block-tunes/block-tune-move-up.ts","webpack://CodexEditor/./src/components/block.js","webpack://CodexEditor/./src/components/dom.js","webpack://CodexEditor/./src/components/inline-tools/inline-tool-bold.ts","webpack://CodexEditor/./src/components/inline-tools/inline-tool-italic.ts","webpack://CodexEditor/./src/components/inline-tools/inline-tool-link.ts","webpack://CodexEditor/./src/components/modules sync ^\\.\\/.*$","webpack://CodexEditor/./src/components/modules/_anchors.js","webpack://CodexEditor/./src/components/modules/_callbacks.js","webpack://CodexEditor/./src/components/modules/_caret.js","webpack://CodexEditor/./src/components/modules/_content.js","webpack://CodexEditor/./src/components/modules/_destroyer.js","webpack://CodexEditor/./src/components/modules/_notifications.js","webpack://CodexEditor/./src/components/modules/_parser.js","webpack://CodexEditor/./src/components/modules/_paste.js","webpack://CodexEditor/./src/components/modules/_transport.js","webpack://CodexEditor/./src/components/modules/api-blocks.ts","webpack://CodexEditor/./src/components/modules/api-events.ts","webpack://CodexEditor/./src/components/modules/api-listener.ts","webpack://CodexEditor/./src/components/modules/api-sanitizer.ts","webpack://CodexEditor/./src/components/modules/api-saver.ts","webpack://CodexEditor/./src/components/modules/api-selection.ts","webpack://CodexEditor/./src/components/modules/api-toolbar.ts","webpack://CodexEditor/./src/components/modules/api.ts","webpack://CodexEditor/./src/components/modules/block-events.ts","webpack://CodexEditor/./src/components/modules/blockManager.js","webpack://CodexEditor/./src/components/modules/caret.js","webpack://CodexEditor/./src/components/modules/events.js","webpack://CodexEditor/./src/components/modules/listeners.js","webpack://CodexEditor/./src/components/modules/renderer.js","webpack://CodexEditor/./src/components/modules/sanitizer.js","webpack://CodexEditor/./src/components/modules/saver.js","webpack://CodexEditor/./src/components/modules/toolbar-blockSettings.js","webpack://CodexEditor/./src/components/modules/toolbar-inline.ts","webpack://CodexEditor/./src/components/modules/toolbar-toolbox.js","webpack://CodexEditor/./src/components/modules/toolbar.js","webpack://CodexEditor/./src/components/modules/toolbar/inline.js","webpack://CodexEditor/./src/components/modules/toolbar/settings.js","webpack://CodexEditor/./src/components/modules/toolbar/toolbar.js","webpack://CodexEditor/./src/components/modules/toolbar/toolbox.js","webpack://CodexEditor/./src/components/modules/tools.js","webpack://CodexEditor/./src/components/modules/ui.js","webpack://CodexEditor/./src/components/polyfills.js","webpack://CodexEditor/./src/components/selection.js","webpack://CodexEditor/./src/components/utils.js","webpack://CodexEditor/./src/styles/main.css"],"names":["modules","editorModules","map","module","CodexEditor","config","moduleInstances","Promise","resolve","then","configuration","init","start","methods","API","method","console","log","catch","error","constructModules","configureModules","forEach","Module","displayName","e","name","state","getModulesDiff","diff","moduleName","prepareDecorator","prepare","Tools","UI","BlockManager","Renderer","render","data","items","initialBlock","type","holderId","placeholder","sanitizer","p","b","a","hideToolbar","tools","toolsConfig","_","isEmpty","length","Editor","new","target","TypeError","DeleteTune","api","CSS","wrapper","button","buttonDelete","buttonConfirm","nodes","resetConfirmation","setConfirmation","$","make","appendChild","svg","listener","on","event","handleClick","needConfirmation","events","off","blocks","delete","classList","add","MoveUpTune","btnDisabled","moveUpButton","getCurrentBlockIndex","currentBlockIndex","currentBlockElement","getBlockByIndex","html","previousBlockElement","currentBlockCoords","getBoundingClientRect","previousBlockCoords","scrollUpOffset","top","Math","abs","window","innerHeight","scrollBy","swap","Block","toolName","toolInstance","settings","apiMethods","tool","_html","compose","tunes","makeTunes","contentNode","content","pluginsContent","methodName","params","Function","call","merge","extractedBlock","save","measuringStart","performance","now","measuringEnd","finishedExtraction","time","isValid","validate","tunesList","tune","tunesElement","document","createDocumentFragment","append","contentless","emptyText","emptyMedia","hasMedia","mediaTags","querySelector","join","selected","remove","Dom","tag","tagName","includes","classNames","attributes","el","createElement","Array","isArray","attrName","createTextNode","width","height","icon","createElementNS","setAttribute","innerHTML","parent","elements","el1","el2","temp","parentNode","insertBefore","removeChild","selector","querySelectorAll","node","atLast","child","sibling","nodeType","Node","ELEMENT_NODE","nodeChild","isSingleTag","getDeepestNode","nativeInputs","nodeText","isElement","isNativeInput","value","textContent","replace","trim","childNodes","treeWalker","leafs","isNodeEmpty","push","firstChild","shift","isLeaf","nextSibling","every","leaf","BoldInlineTool","commandName","buttonActive","buttonModifier","range","execCommand","selection","isActive","queryCommandState","toggle","ItalicInlineTool","LinkInlineTool","commandLink","commandUnlink","ENTER_KEY","buttonUnlink","input","inputShowed","inputOpened","inlineToolbar","toolbar","Selection","addEventListener","keyCode","enterPressed","parentAnchor","findParentTag","expandToTag","unlink","closeActions","checkState","close","toggleActions","anchorTag","openActions","hrefAttr","getAttribute","needFocus","focus","clearSavedSelection","clearSaved","restore","preventDefault","validateURL","prepareLink","insertLink","stopPropagation","stopImmediatePropagation","str","test","link","addProtocol","isInternal","isAnchor","substring","isProtocolRelative","exports","anchors","editor","codex","currentNode","settingsOpened","currentBlock","dataset","anchor","anchorChanged","newAnchor","rusToTranslit","ui","className","BLOCK_WITH_ANCHOR","keyDownOnAnchorInput","core","keys","ENTER","blur","keyUpOnAnchorInput","LEFT","DOWN","string","ru","en","i","split","toLowerCase","callbacks","globalKeydown","enterKeyPressed_","redactorKeyDown","TAB","tabKeyPressedOnRedactorsZone_","enterKeyPressedOnRedactorsZone_","ESC","escapeKeyPressedOnRedactorsZone_","defaultKeyPressedOnRedactorsZone_","globalKeyup","UP","RIGHT","arrowKeyPressed_","isBlockEmpty","opened","open","toolbox","editorAreaHightlighted","caret","inputIndex","enterPressedOnBlock_","NEW_BLOCK_TYPE","initialBlockPlugin","insertBlock","block","move","contentEditable","saveCurrentInputIndex","currentInputIndex","getCurrentInputIndex","workingNode","isEnterPressedOnToolbar","current","inputs","enableLineBreaks","toolClicked","shiftKey","currentSelection","getSelection","currentSelectedNode","anchorNode","caretAtTheEndOfText","position","atTheEnd","isTextNodeHasParentBetweenContenteditable","callback","enterPressedOnBlock","nodeTypes","TEXT","splitBlock","showPlusButton","islastNode","isLastNode","saveInputs","workingNodeChanged","inline","actionsOpened","clearMark","redactorClicked","detectWhenClickedOnFirstLevelBlockArea_","selectedText","getSelectionText","firstLevelBlock","indexOfLastInput","getFirstLevelBlock","setToBlock","setToNextBlock","inputIsEmpty","currentNodeType","isInitialType","hidePlusButton","markBlock","flag","rangeCount","isDomNode","body","toolbarButtonClicked","plusButtonClicked","contains","blockKeydown","blockRightOrDownArrowPressed_","BACKSPACE","backspacePressed_","blockLeftOrUpArrowPressed_","focusedNode","focusedNodeHolder","editableElementIndex","caretInLastChild","lastChild","deepestTextnode","getDeepestTextNodeFromPosition","anchorOffset","caretInFirstChild","caretAtTheBeginning","setToPreviousBlock","selectionLength","firstLevelBlocksCount","getRange","endOffset","startOffset","atStart","mergeBlocks","redactor","addInitialBlock","setTimeout","showSettingsButtonClicked","currentToolType","hideRemoveActions","offset","focusedNodeIndex","set","index","childs","nodeToSet","createRange","setStart","setEnd","removeAllRanges","addRange","nextInput","emptyTextElement","targetInput","previousInput","lastChildNode","lengthOfLastChildNode","pluginsRender","isFirstNode","isOffsetZero","insertNode","lastNode","DOCUMENT_FRAGMENT","getRangeAt","deleteContents","setStartAfter","collapse","stretched","highlighted","_currentNode","_currentIndex","pluginHTML","isStretched","blockContent","toolId","newBlock","composeBlock_","insertAdjacentElement","destroyer","removeNodes","notifications","destroyPlugins","destroy","destroyScripts","scripts","getElementsByTagName","id","indexOf","scriptPrefix","listeners","removeAll","plugins","queue","addToQueue","splice","createHolder","holder","draw","errorThrown","errorMsg","notification","message","constructorSettings","cancel","confirm","inputField","confirmHandler","cancelHandler","create","okBtn","cancelBtn","okMsg","cancelMsg","send","clear","parser","insertPastedContent","blockType","text","isFirstLevelBlock","TAG","BLOCK_CLASSNAME","paste","patterns","renderOnPastePatterns","pattern","pasted","clipBoardData","clipboardData","getData","result","analize","plugin","execArray","regex","exec","match","pasteToNewBlock_","blockPasteCallback","needsToHandlePasteEvent","htmlData","plainData","paragraphs","cleanData","wrappedData","clean","wrapTextWithParagraphs","emulateUserAgentBehaviour","insertPastedParagraphs","editableParent","getEditableParent","paragraph","newNode","childElementCount","cloneNode","transport","currentRequest","arguments","fileSelected","clearInput","files","formData","FormData","multiple","ajax","url","beforeSend","success","progress","selectAndUpload","args","accept","click","abort","BlocksAPI","fromIndex","toIndex","Toolbar","blockIndex","removeBlock","insert","Caret","navigatePrevious","EventsAPI","eventName","Events","emit","ListenerAPI","element","eventType","handler","useCapture","Listeners","SanitizerAPI","taintString","Sanitizer","SaverAPI","Saver","SelectionAPI","ToolbarAPI","saver","BlockEvents","keyCodes","backspace","enter","arrowRightAndDownPressed","arrowLeftAndUpPressed","InlineToolbar","handleShowingEvent","apiSettings","IS_ENABLED_LINE_BREAKS","newCurrent","isInitial","plusButton","show","BM","isFirstBlock","canMergeBlocks","isAtStart","targetBlock","blockToMerge","mergeable","setCaretToTheEnd","navigateNext","_blocks","Blocks","Proxy","get","construct","bindEvents","keydown","mouseUp","keyup","composeBlock","blockToMergeIndex","blockToMergeInfo","mergeWith","extractedFragment","extractFragmentFromCaretPosition","blockInserted","closest","childNode","parentFirstLevelBlock","Error","needAddInitialBlock","isLastBlock","array","workingArea","first","second","secondBlock","deleteCount","previousBlock","nextBlock","isNaN","children","instance","Number","atEnd","delay","lastBlock","selectRange","blockElem","cloneRange","selectNodeContents","endContainer","extractContents","from","direction","siblings","force","isAtEnd","isCollapsed","firstNode","firstLetterPosition","search","leftSiblings","getHigherLevelSiblings","nothingAtLeft","nothingAtRight","rightTrimmedText","subscribers","reduce","previousData","currentHandler","newData","allListeners","assignedEventData","alreadyExist","findOne","existingListeners","findAll","removeEventListener","listenersOnElement","listenersWithType","listenersWithHandler","foundListeners","found","foundByElements","findByElement","filter","chainData","function","sequence","item","available","defaultConfig","_sanitizerInstance","sanitizerConfig","sanitizerInstance","require","customConfig","library","tags","href","rel","newInstance","output","blocksData","all","allExtractedData","makeOutput","outputData","totalTime","groupCollapsed","extraction","groupEnd","Date","version","VERSION","BlockSettings","toolSettings","defaultSettings","makeSettings","renderTunes","wrapperOpened","addToolSettings","addDefaultSettings","closed","inlineToolbarShowed","buttonsWrapper","actionsWrapper","buttons","actions","toolbarVerticalMargin","addTools","allowedToShow","checkToolsState","selectionRect","rect","wrapperOffset","newCoords","x","left","y","floor","style","tagsConflictsWithSelection","getBlock","toolConfig","IS_ENABLED_INLINE_TOOLBAR","addTool","renderActions","surround","toolsInstances","Tool","Toolbox","toolsAvailable","IS_DISPLAYED_IN_TOOLBOX","TOOLBAR_ICON_CLASS","toolboxButton","title","buttonClicked","toolButton","toolClasses","IS_IRREPLACEBLE_TOOL","toolboxOpened","blockActionsButtons","settingsToggler","settingsIcon","forceClose","defaultToolbarHeight","defaultOffset","newYCoordinate","offsetTop","transform","toolbarOpened","settingsTogglerClicked","hide","plusButtonHidden","buttonsOpened","wrappersOffset","storedSelection","showInlineToolbar","showButtons","getWrappersOffset","coords","getSelectionCoords","newCoordinateX","newCoordinateY","offsetHeight","scrollY","closeButtons","closeAction","createLinkAction","defaultToolAction","hightlight","getOffset","_x","_y","offsetLeft","clientLeft","clientTop","offsetParent","sel","boundingLeft","boundingTop","getClientRects","toString","showActions","action","inlineToolbarAnchorInputKeydown_","editable","restoreSelection","setAnchor","clearRange","isLinkActive","saveSelection","inputForLink","dataType","containerEl","preSelectionRange","startContainer","end","savedSel","charIndex","nodeStack","foundStart","stop","nextCharIndex","pop","setButtonHighlighted","removeButtonsHighLight","setting","toolType","settingsBlock","pluginSettings","blockSettings","makeRemoveBlockButton","removeBlockWrapper","settingButton","actionWrapper","confirmAction","cancelAction","removeButtonClicked","confirmRemovingRequest","cancelRemovingRequest","showRemoveActions","showSettingsButton","toolbarButtons","openedOnBlock","currentTool","Object","barButtons","nextToolIndex","toolToSelect","visibleTool","displayInToolbox","UNREPLACEBLE_TOOLS","newBlockContent","appendCallback","blockData","switchBlock","toolsUnavailable","values","IS_INLINE","inlineToolRequiredMethods","notImplementedMethods","hasOwnProperty","reject","sequenceData","getListOfPrepareFunctions","fallback","toolPreparationList","toolClass","appendSVGSprite","loadStyles","getElementById","editorWrapper","editorZone","styles","head","documentClicked","clickedOnInlineToolbarButton","clickedNode","setCurrentBlockByChildNode","setToTheLastBlock","isInitialBlock","isEmptyBlock","spriteHolder","sprite","Element","prototype","matches","msMatchesSelector","webkitMatchesSelector","s","documentElement","parentElement","savedSelectionRange","searchDepth","parentTag","focusNode","boundNodes","searchDepthIterable","boundingWidth","boundingHeight","span","spanParent","normalize","Util","msg","chains","previousValue","currentValue","iteration","waitNextBlock","successCallback","fallbackCallback","collection","slice","object","constructor","timeout","context","apply","SHIFT","CTRL","ALT","SPACE","DELETE","META"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;ACVA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,kDAA0C,gCAAgC;AAC1E;AACA;;AAEA;AACA;AACA;AACA,gEAAwD,kBAAkB;AAC1E;AACA,yDAAiD,cAAc;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAyC,iCAAiC;AAC1E,wHAAgH,mBAAmB,EAAE;AACrI;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;;AAGA;AACA;;;;;;;;;;;;AClFA,whI;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,mCAAmC,gBAAgB;AACnD,IAAI;AACJ;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,gBAAgB,iBAAiB;AACjC;AACA;AACA;AACA;AACA,YAAY,oBAAoB;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,oDAAoD,cAAc;;AAElE;AACA;;;;;;;;;;;;AC3EA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA,GAAG,QAIH;AACA,CAAC;;AAED;AACA,aAAa,OAAO;AACpB,aAAa,QAAQ;AACrB;AACA;;AAEA;AACA;;AAEA;AACA,wBAAwB,iCAAiC,EAAE;AAC3D,6BAA6B,uEAAuE,EAAE;;AAEtG;AACA;AACA;;AA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AKjC,MAAL,CAAYiC,IAAZ,CAAiBC,KAAjB,GAAyB,CAAEC,YAAF,CAAzB;AACD,OAHD,MAGO;AACL,YAAI,CAAC,KAAKnC,MAAL,CAAYiC,IAAZ,CAAiBC,KAAlB,IAA2B,KAAKlC,MAAL,CAAYiC,IAAZ,CAAiBC,KAAjB,CAAuBc,MAAvB,KAAkC,CAAjE,EAAoE;AAClE,eAAKhD,MAAL,CAAYiC,IAAZ,CAAiBC,KAAjB,GAAyB,CAAEC,YAAF,CAAzB;AACD;AACF;;AAED;;;AAGA,UAAI,CAACnC,OAAOmC,YAAZ,EAA0B;AACxB,aAAK,KAAKnC,MAAL,CAAYmC,YAAjB,IAAiC,KAAKnC,MAAL,CAAY4C,KAA7C;AAAoD;AAApD;AACD,OAFD,MAEO;AACL,aAAK5C,MAAL,CAAYmC,YAAZ,GAA2BnC,OAAOmC,YAAlC;AACD;AACF;;AAED;;;;;wBAIoB;AAClB,aAAO,KAAKnC,MAAZ;AACD;;;;;;;kBAjHkBD,W;AA4MpB;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;ACjZA;;;;;;;;;IASqBmB,M;AACjB;;;;;AAKA,wBAAwB;AAAA,QAAVlB,MAAU,QAAVA,MAAU;;AAAA;;AACpB;;;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IAAP;AACD;AACF;AAxGH;AAAA;;;AA0GE;;;;;;;;AA1GF,gCAkHclE,IAlHd,EAkHoB;AAChB,UAAIoU,WAAW,KAAKC,aAAL,CAAmBrU,IAAnB,CAAf;;AAEA,UAAI,KAAK2J,WAAT,EAAsB;AACpB,aAAKA,WAAL,CAAiB2K,qBAAjB,CAAuC,UAAvC,EAAmDF,QAAnD;AACD,OAFD,MAEO;AACL;;;AAGA,aAAK1X,MAAL,CAAYyN,EAAZ,CAAe9M,KAAf,CAAqBsU,QAArB,CAA8BjU,WAA9B,CAA0C0W,QAA1C;AACD;;AAED;;;AAGA,WAAKzK,WAAL,GAAmByK,QAAnB;;AAEA,aAAOA,SAAStK,OAAT,CAAiBqK,MAAxB;AACD;AApIH;AAAA;AAAA,sBAiCYzX,MAjCZ,EAiCoB;AAChB,WAAKA,MAAL,GAAcA,MAAd;AACD;;AAED;;;;;;AArCF;AAAA;AAAA,wBA0CoB;AAChB,aAAO,KAAKoX,YAAZ;AACD;;AAED;;;;;AA9CF;AAAA,sBAmDkB5P,IAnDlB,EAmDwB;AACpB,UAAIiL,kBAAkB,KAAKE,kBAAL,CAAwBnL,IAAxB,CAAtB;;AAEA,WAAK4P,YAAL,GAAoB3E,eAApB;AACD;AAvDH;;AAAA;AAAA;;AAuIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,U;;;;;;;;;;;;;;;;AC56BA;;;;;;;AAOA5V,OAAOgQ,OAAP,GAAiB,UAAUgL,SAAV,EAAqB;AACpC,MAAI9K,SAASC,MAAMD,MAAnB;;AAEA8K,YAAUC,WAAV,GAAwB,YAAY;AAClC/K,WAAOpM,KAAP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T3J,gBAAMioB,WAAW9jB,IADR;AAETtE,gBAAMooB,WAAWpoB;AAFR,SAAX;AAID,OARD;;AAUAtB,cAAQC,GAAR,CAAY,OAAZ,EAAqBupB,SAArB;AACAxpB,cAAQ2pB,QAAR;;AAEA,aAAO;AACL3iB,cAAU,CAAC,IAAI4iB,IAAJ,EADN;AAELroB,eAAUA,KAFL;AAGLsoB,iBAAU,OAAAC;AAHL,OAAP;AAKD;;;;EA5DgCvpB,M;;AA+DnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;kBA5NqBmhB,K;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtBrB;;;;;;;;;;;IAWqBqI,a;;;AACnB;;;AAGA,+BAAsB;AAAA,QAAT1qB,MAAS,QAATA,MAAS;;AAAA;;AAAA,8HACd,EAACA,cAAD,EADc;;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oBoC,UAApB,CAA+BC,IAA/B;AACD;AACF;;AAED;;;;;;sCAGkB;AAChB,UAAI6R,eAAepxB,EAAEC,IAAF,CAAO,KAAP,CAAnB;;AAEAmxB,mBAAarrB,SAAb,GAAyBsrB,gBAAzB;;AAEArxB,QAAEoE,MAAF,CAAS,KAAKvE,KAAL,CAAWJ,OAApB,EAA6B2xB,YAA7B;AACD;;;wBA/NS;AACR,aAAO;AACLX,uBAAgB,cADX;AAELC,oBAAgB;AAFX,OAAP;AAID;;;;EAtE6BvzB,M;;AAmShC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA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","file":"codex-editor.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"CodexEditor\"] = factory();\n\telse\n\t\troot[\"CodexEditor\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/codex.js\");\n","module.exports = \"\\n\\n\\r\\n \\r\\n\\n\\n\\r\\n \\r\\n\\n\\n\\r\\n \\r\\n\\n\\n\\r\\n \\r\\n\\n\\n\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\n\\n\\r\\n \\r\\n\\n\\n\\r\\n \\r\\n\\n\\n\\r\\n \\r\\n\\n\\n\\r\\n \\r\\n\\n\"","/*\n\tMIT License http://www.opensource.org/licenses/mit-license.php\n\tAuthor Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\nmodule.exports = function(useSourceMap) {\n\tvar list = [];\n\n\t// return the list of modules as css string\n\tlist.toString = function toString() {\n\t\treturn this.map(function (item) {\n\t\t\tvar content = cssWithMappingToString(item, useSourceMap);\n\t\t\tif(item[2]) {\n\t\t\t\treturn \"@media \" + item[2] + \"{\" + content + \"}\";\n\t\t\t} else {\n\t\t\t\treturn content;\n\t\t\t}\n\t\t}).join(\"\");\n\t};\n\n\t// import a list of modules into the list\n\tlist.i = function(modules, mediaQuery) {\n\t\tif(typeof modules === \"string\")\n\t\t\tmodules = [[null, modules, \"\"]];\n\t\tvar alreadyImportedModules = {};\n\t\tfor(var i = 0; i < this.length; i++) {\n\t\t\tvar id = this[i][0];\n\t\t\tif(typeof id === \"number\")\n\t\t\t\talreadyImportedModules[id] = true;\n\t\t}\n\t\tfor(i = 0; i < modules.length; i++) {\n\t\t\tvar item = modules[i];\n\t\t\t// skip already imported module\n\t\t\t// this implementation is not 100% perfect for weird media query combinations\n\t\t\t// when a module is imported multiple times with different media queries.\n\t\t\t// I hope this will never occur (Hey this way we have smaller bundles)\n\t\t\tif(typeof item[0] !== \"number\" || !alreadyImportedModules[item[0]]) {\n\t\t\t\tif(mediaQuery && !item[2]) {\n\t\t\t\t\titem[2] = mediaQuery;\n\t\t\t\t} else if(mediaQuery) {\n\t\t\t\t\titem[2] = \"(\" + item[2] + \") and (\" + mediaQuery + \")\";\n\t\t\t\t}\n\t\t\t\tlist.push(item);\n\t\t\t}\n\t\t}\n\t};\n\treturn list;\n};\n\nfunction cssWithMappingToString(item, useSourceMap) {\n\tvar content = item[1] || '';\n\tvar cssMapping = item[3];\n\tif (!cssMapping) {\n\t\treturn content;\n\t}\n\n\tif (useSourceMap && typeof btoa === 'function') {\n\t\tvar sourceMapping = toComment(cssMapping);\n\t\tvar sourceURLs = cssMapping.sources.map(function (source) {\n\t\t\treturn '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'\n\t\t});\n\n\t\treturn [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n\t}\n\n\treturn [content].join('\\n');\n}\n\n// Adapted from convert-source-map (MIT)\nfunction toComment(sourceMap) {\n\t// eslint-disable-next-line no-undef\n\tvar base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n\tvar data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;\n\n\treturn '/*# ' + data + ' */';\n}\n","(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n define('html-janitor', factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.HTMLJanitor = factory();\n }\n}(this, function () {\n\n /**\n * @param {Object} config.tags Dictionary of allowed tags.\n * @param {boolean} config.keepNestedBlockElements Default false.\n */\n function HTMLJanitor(config) {\n\n var tagDefinitions = config['tags'];\n var tags = Object.keys(tagDefinitions);\n\n var validConfigValues = tags\n .map(function(k) { return typeof tagDefinitions[k]; })\n .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; });\n\n if(!validConfigValues) {\n throw new Error(\"The configuration was invalid\");\n }\n\n this.config = config;\n }\n\n // TODO: not exhaustive?\n var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE'];\n function isBlockElement(node) {\n return blockElementNames.indexOf(node.nodeName) !== -1;\n }\n\n var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE'];\n function isInlineElement(node) {\n return inlineElementNames.indexOf(node.nodeName) !== -1;\n }\n\n HTMLJanitor.prototype.clean = function (html) {\n var sandbox = document.createElement('div');\n sandbox.innerHTML = html;\n\n this._sanitize(sandbox);\n\n return sandbox.innerHTML;\n };\n\n HTMLJanitor.prototype._sanitize = function (parentNode) {\n var treeWalker = createTreeWalker(parentNode);\n var node = treeWalker.firstChild();\n if (!node) { return; }\n\n do {\n // Ignore nodes that have already been sanitized\n if (node._sanitized) {\n continue;\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n // If this text node is just whitespace and the previous or next element\n // sibling is a block element, remove it\n // N.B.: This heuristic could change. Very specific to a bug with\n // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output\n // FIXME: make this an option?\n if (node.data.trim() === ''\n && ((node.previousElementSibling && isBlockElement(node.previousElementSibling))\n || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) {\n parentNode.removeChild(node);\n this._sanitize(parentNode);\n break;\n } else {\n continue;\n }\n }\n\n // Remove all comments\n if (node.nodeType === Node.COMMENT_NODE) {\n parentNode.removeChild(node);\n this._sanitize(parentNode);\n break;\n }\n\n var isInline = isInlineElement(node);\n var containsBlockElement;\n if (isInline) {\n containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement);\n }\n\n // Block elements should not be nested (e.g.
  • ...); if\n // they are, we want to unwrap the inner block element.\n var isNotTopContainer = !! parentNode.parentNode;\n var isNestedBlockElement =\n isBlockElement(parentNode) &&\n isBlockElement(node) &&\n isNotTopContainer;\n\n var nodeName = node.nodeName.toLowerCase();\n\n var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\n var isInvalid = isInline && containsBlockElement;\n\n // Drop tag entirely according to the whitelist *and* if the markup\n // is invalid.\n if (isInvalid || shouldRejectNode(node, allowedAttrs)\n || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n // Do not keep the inner text of SCRIPT/STYLE elements.\n if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n while (node.childNodes.length > 0) {\n parentNode.insertBefore(node.childNodes[0], node);\n }\n }\n parentNode.removeChild(node);\n\n this._sanitize(parentNode);\n break;\n }\n\n // Sanitize attributes\n for (var a = 0; a < node.attributes.length; a += 1) {\n var attr = node.attributes[a];\n\n if (shouldRejectAttr(attr, allowedAttrs, node)) {\n node.removeAttribute(attr.name);\n // Shift the array to continue looping.\n a = a - 1;\n }\n }\n\n // Sanitize children\n this._sanitize(node);\n\n // Mark node as sanitized so it's ignored in future runs\n node._sanitized = true;\n } while ((node = treeWalker.nextSibling()));\n };\n\n function createTreeWalker(node) {\n return document.createTreeWalker(node,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n null, false);\n }\n\n function getAllowedAttrs(config, nodeName, node){\n if (typeof config.tags[nodeName] === 'function') {\n return config.tags[nodeName](node);\n } else {\n return config.tags[nodeName];\n }\n }\n\n function shouldRejectNode(node, allowedAttrs){\n if (typeof allowedAttrs === 'undefined') {\n return true;\n } else if (typeof allowedAttrs === 'boolean') {\n return !allowedAttrs;\n }\n\n return false;\n }\n\n function shouldRejectAttr(attr, allowedAttrs, node){\n var attrName = attr.name.toLowerCase();\n\n if (allowedAttrs === true){\n return false;\n } else if (typeof allowedAttrs[attrName] === 'function'){\n return !allowedAttrs[attrName](attr.value, node);\n } else if (typeof allowedAttrs[attrName] === 'undefined'){\n return true;\n } else if (allowedAttrs[attrName] === false) {\n return true;\n } else if (typeof allowedAttrs[attrName] === 'string') {\n return (allowedAttrs[attrName] !== attr.value);\n }\n\n return false;\n }\n\n return HTMLJanitor;\n\n}));\n","/**\r\n * Codex Editor\r\n *\r\n * Short Description (눈_눈;)\r\n * @version 2.0.0\r\n *\r\n * How to start?\r\n * Example:\r\n * new CodexEditor({\r\n * holderId : 'codex-editor',\r\n * initialBlock : 'text',\r\n * placeholder : 'Write your story....',\r\n * tools: {\r\n * quote: Quote,\r\n * anotherTool : AnotherTool\r\n * },\r\n * toolsConfig: {\r\n * quote: {\r\n * iconClassname : 'quote-icon',\r\n * displayInToolbox : true,\r\n * enableLineBreaks : true\r\n * },\r\n * anotherTool: {\r\n * iconClassname : 'tool-icon'\r\n * }\r\n * }\r\n * });\r\n *\r\n * - tools is an object: {\r\n * pluginName: PluginClass,\r\n * .....\r\n * }\r\n * - toolsConfig is an additional configuration that uses Codex Editor API\r\n * iconClassname - CSS classname of toolbox icon\r\n * displayInToolbox - if you want to see your Tool in toolbox hided in \"plus\" button, than set \"True\". By default : \"False\"\r\n * enableLineBreaks - by default enter creates new block that set as initialblock, but if you set this property \"True\", enter will break the lines in current block\r\n *\r\n * @author CodeX-Team \r\n *\r\n */\r\n\r\n/**\r\n * @typedef {CodexEditor} CodexEditor - editor class\r\n */\r\n\r\n/**\r\n * @typedef {Object} EditorConfig\r\n * @property {String} holderId - Element to append Editor\r\n * @property {Array} data - Blocks list in JSON-format\r\n * @property {Object} tools - Map for used Tools in format { name : Class, ... }\r\n * @property {String} initialBlock - This Tool will be added by default\r\n * @property {String} placeholder - First Block placeholder\r\n * @property {Object} sanitizer - @todo fill desc\r\n * @property {Boolean} hideToolbar - @todo fill desc\r\n * @property {Object} toolsConfig - tools configuration {@link tools#ToolConfig}\r\n */\r\n\r\n/**\r\n * Dynamically imported utils\r\n *\r\n * @typedef {Dom} $ - {@link components/dom.js}\r\n * @typedef {Util} _ - {@link components/utils.js}\r\n */\r\n\r\n'use strict';\r\n\r\n/**\r\n * Apply polyfills\r\n */\r\nimport 'components/polyfills';\r\n\r\n/**\r\n * Require Editor modules places in components/modules dir\r\n */\r\n// eslint-disable-next-line\r\nlet modules = editorModules.map( module => require('./components/modules/' + module ));\r\n\r\n/**\r\n * @class\r\n *\r\n * @classdesc CodeX Editor base class\r\n *\r\n * @property this.config - all settings\r\n * @property this.moduleInstances - constructed editor components\r\n *\r\n * @type {CodexEditor}\r\n */\r\nexport default class CodexEditor {\r\n /** Editor version */\r\n static get version() {\r\n return VERSION;\r\n }\r\n\r\n /**\r\n * @param {EditorConfig} config - user configuration\r\n *\r\n */\r\n constructor(config) {\r\n /**\r\n * Configuration object\r\n * @type {EditorConfig}\r\n */\r\n this.config = {};\r\n\r\n /**\r\n * @typedef {Object} EditorComponents\r\n * @property {BlockManager} BlockManager\r\n * @property {Tools} Tools\r\n * @property {Events} Events\r\n * @property {UI} UI\r\n * @property {Toolbar} Toolbar\r\n * @property {Toolbox} Toolbox\r\n * @property {BlockSettings} BlockSettings\r\n * @property {Renderer} Renderer\r\n * @property {InlineToolbar} InlineToolbar\r\n */\r\n this.moduleInstances = {};\r\n\r\n Promise.resolve()\r\n .then(() => {\r\n this.configuration = config;\r\n })\r\n .then(() => this.init())\r\n .then(() => this.start())\r\n .then(() => {\r\n let methods = this.moduleInstances.API.methods;\r\n\r\n /**\r\n * Make API methods available from inside easier\r\n */\r\n for (let method in methods) {\r\n this[method] = methods[method];\r\n }\r\n\r\n delete this.moduleInstances; // todo Is it necessary?\r\n })\r\n .then(() => {\r\n console.log('CodeX Editor is ready!');\r\n })\r\n .catch(error => {\r\n console.log('CodeX Editor does not ready because of %o', error);\r\n });\r\n }\r\n\r\n /**\r\n * Setting for configuration\r\n * @param {EditorConfig} config\r\n */\r\n set configuration(config) {\r\n /**\r\n * Initlai block type\r\n * Uses in case when there is no items passed\r\n * @type {{type: (*), data: {text: null}}}\r\n */\r\n let initialBlock = {\r\n type : config.initialBlock,\r\n data : {}\r\n };\r\n\r\n this.config.holderId = config.holderId;\r\n this.config.placeholder = config.placeholder || 'write your story...';\r\n this.config.sanitizer = config.sanitizer || {\r\n p: true,\r\n b: true,\r\n a: true\r\n };\r\n\r\n this.config.hideToolbar = config.hideToolbar ? config.hideToolbar : false;\r\n this.config.tools = config.tools || {};\r\n this.config.toolsConfig = config.toolsConfig || {};\r\n this.config.data = config.data || {};\r\n\r\n /**\r\n * Initialize items to pass data to the Renderer\r\n */\r\n if (_.isEmpty(this.config.data)) {\r\n this.config.data = {};\r\n this.config.data.items = [ initialBlock ];\r\n } else {\r\n if (!this.config.data.items || this.config.data.items.length === 0) {\r\n this.config.data.items = [ initialBlock ];\r\n }\r\n }\r\n\r\n /**\r\n * If initial Block's Tool was not passed, use the first Tool in config.tools\r\n */\r\n if (!config.initialBlock) {\r\n for (this.config.initialBlock in this.config.tools) break;\r\n } else {\r\n this.config.initialBlock = config.initialBlock;\r\n }\r\n }\r\n\r\n /**\r\n * Returns private property\r\n * @returns {EditorConfig}\r\n */\r\n get configuration() {\r\n return this.config;\r\n }\r\n\r\n /**\r\n * Initializes modules:\r\n * - make and save instances\r\n * - configure\r\n */\r\n init() {\r\n /**\r\n * Make modules instances and save it to the @property this.moduleInstances\r\n */\r\n this.constructModules();\r\n\r\n /**\r\n * Modules configuration\r\n */\r\n this.configureModules();\r\n }\r\n\r\n /**\r\n * Make modules instances and save it to the @property this.moduleInstances\r\n */\r\n constructModules() {\r\n modules.forEach( Module => {\r\n try {\r\n /**\r\n * We use class name provided by displayName property\r\n *\r\n * On build, Babel will transform all Classes to the Functions so, name will always be 'Function'\r\n * To prevent this, we use 'babel-plugin-class-display-name' plugin\r\n * @see https://www.npmjs.com/package/babel-plugin-class-display-name\r\n */\r\n this.moduleInstances[Module.displayName] = new Module({\r\n config : this.configuration\r\n });\r\n } catch ( e ) {\r\n console.log('Module %o skipped because %o', Module, e);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Modules instances configuration:\r\n * - pass other modules to the 'state' property\r\n * - ...\r\n */\r\n configureModules() {\r\n for(let name in this.moduleInstances) {\r\n /**\r\n * Module does not need self-instance\r\n */\r\n this.moduleInstances[name].state = this.getModulesDiff( name );\r\n }\r\n }\r\n\r\n /**\r\n * Return modules without passed name\r\n */\r\n getModulesDiff( name ) {\r\n let diff = {};\r\n\r\n for(let moduleName in this.moduleInstances) {\r\n /**\r\n * Skip module with passed name\r\n */\r\n if (moduleName === name) {\r\n continue;\r\n }\r\n diff[moduleName] = this.moduleInstances[moduleName];\r\n }\r\n\r\n return diff;\r\n }\r\n\r\n /**\r\n * Start Editor!\r\n *\r\n * Get list of modules that needs to be prepared and return a sequence (Promise)\r\n * @return {Promise}\r\n */\r\n start() {\r\n let prepareDecorator = module => module.prepare();\r\n\r\n return Promise.resolve()\r\n .then(prepareDecorator(this.moduleInstances.Tools))\r\n .then(prepareDecorator(this.moduleInstances.UI))\r\n .then(prepareDecorator(this.moduleInstances.BlockManager))\r\n .then(() => {\r\n return this.moduleInstances.Renderer.render(this.config.data.items);\r\n });\r\n }\r\n};\r\n\r\n// module.exports = (function (editor) {\r\n//\r\n// 'use strict';\r\n//\r\n// editor.version = VERSION;\r\n// editor.scriptPrefix = 'cdx-script-';\r\n//\r\n// var init = function () {\r\n//\r\n// editor.core = require('./modules/core');\r\n// editor.tools = require('./modules/tools');\r\n// editor.ui = require('./modules/ui');\r\n// editor.transport = require('./modules/transport');\r\n// editor.renderer = require('./modules/renderer');\r\n// editor.saver = require('./modules/saver');\r\n// editor.content = require('./modules/content');\r\n// editor.toolbar = require('./modules/toolbar/toolbar');\r\n// editor.callback = require('./modules/callbacks');\r\n// editor.draw = require('./modules/draw');\r\n// editor.caret = require('./modules/caret');\r\n// editor.notifications = require('./modules/notifications');\r\n// editor.parser = require('./modules/parser');\r\n// editor.sanitizer = require('./modules/sanitizer');\r\n// editor.listeners = require('./modules/listeners');\r\n// editor.destroyer = require('./modules/destroyer');\r\n// editor.paste = require('./modules/paste');\r\n//\r\n// };\r\n//\r\n// /**\r\n// * @public\r\n// * holds initial settings\r\n// */\r\n// editor.settings = {\r\n// tools : ['text', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\r\n// holderId : 'codex-editor',\r\n//\r\n// // Type of block showing on empty editor\r\n// initialBlockPlugin: 'text'\r\n// };\r\n//\r\n// /**\r\n// * public\r\n// *\r\n// * Static nodes\r\n// */\r\n// editor.nodes = {\r\n// holder : null,\r\n// wrapper : null,\r\n// toolbar : null,\r\n// inlineToolbar : {\r\n// wrapper : null,\r\n// buttons : null,\r\n// actions : null\r\n// },\r\n// toolbox : null,\r\n// notifications : null,\r\n// plusButton : null,\r\n// showSettingsButton: null,\r\n// showTrashButton : null,\r\n// blockSettings : null,\r\n// pluginSettings : null,\r\n// defaultSettings : null,\r\n// toolbarButtons : {}, // { type : DomEl, ... }\r\n// redactor : null\r\n// };\r\n//\r\n// /**\r\n// * @public\r\n// *\r\n// * Output state\r\n// */\r\n// editor.state = {\r\n// jsonOutput : [],\r\n// blocks : [],\r\n// inputs : []\r\n// };\r\n//\r\n// /**\r\n// * @public\r\n// * Editor plugins\r\n// */\r\n// editor.tools = {};\r\n//\r\n// editor.start = function (userSettings) {\r\n//\r\n// init();\r\n//\r\n// editor.core.prepare(userSettings)\r\n//\r\n// // If all ok, make UI, bind events and parse initial-content\r\n// .then(editor.ui.prepare)\r\n// .then(editor.tools.prepare)\r\n// .then(editor.sanitizer.prepare)\r\n// .then(editor.paste.prepare)\r\n// .then(editor.transport.prepare)\r\n// .then(editor.renderer.makeBlocksFromData)\r\n// .then(editor.ui.saveInputs)\r\n// .catch(function (error) {\r\n//\r\n// editor.core.log('Initialization failed with error: %o', 'warn', error);\r\n//\r\n// });\r\n//\r\n// };\r\n//\r\n// return editor;\r\n//\r\n// })({});\r\n","/**\r\n * @abstract\r\n * @class Module\r\n * @classdesc All modules inherits from this class.\r\n *\r\n * @typedef {Module} Module\r\n * @property {Object} config - Editor user settings\r\n * @property {Object} Editor - List of Editor modules\r\n */\r\nexport default class Module {\r\n /**\r\n * @constructor\r\n *\r\n * @param {EditorConfig} config\r\n */\r\n constructor({ config }) {\r\n /**\r\n * Editor modules list\r\n * @type {EditorComponents}\r\n */\r\n this.Editor = null;\r\n /**\r\n * Editor configuration object\r\n * @type {EditorConfig}\r\n */\r\n this.config = {};\r\n if (new.target === Module) {\r\n throw new TypeError('Constructors for abstract class Module are not allowed.');\r\n }\r\n this.config = config;\r\n }\r\n /**\r\n * Editor modules setter\r\n *\r\n * @param Editor\r\n * @param Editor.modules {@link CodexEditor#moduleInstances}\r\n * @param Editor.config {@link CodexEditor#configuration}\r\n */\r\n set state(Editor) {\r\n this.Editor = Editor;\r\n }\r\n}\r\n","export default class DeleteTune {\r\n /**\r\n * DeleteTune constructor\r\n *\r\n * @param {Object} api\r\n */\r\n constructor({ api }) {\r\n /**\r\n * Styles\r\n * @type {{wrapper: string}}\r\n */\r\n this.CSS = {\r\n wrapper: 'ass',\r\n button: 'ce-settings__button',\r\n buttonDelete: 'ce-settings__button--delete',\r\n buttonConfirm: 'ce-settings__button--confirm',\r\n };\r\n /**\r\n * Tune nodes\r\n */\r\n this.nodes = {\r\n button: null,\r\n };\r\n this.api = api;\r\n this.resetConfirmation = () => {\r\n this.setConfirmation(false);\r\n };\r\n }\r\n /**\r\n * Create \"Delete\" button and add click event listener\r\n * @returns [Element}\r\n */\r\n render() {\r\n this.nodes.button = $.make('div', [this.CSS.button, this.CSS.buttonDelete], {});\r\n this.nodes.button.appendChild($.svg('cross', 12, 12));\r\n this.api.listener.on(this.nodes.button, 'click', (event) => this.handleClick(event), false);\r\n return this.nodes.button;\r\n }\r\n /**\r\n * Delete block conditions passed\r\n * @param {MouseEvent} event\r\n */\r\n handleClick(event) {\r\n /**\r\n * if block is not waiting the confirmation, subscribe on block-settings-closing event to reset\r\n * otherwise delete block\r\n */\r\n if (!this.needConfirmation) {\r\n this.setConfirmation(true);\r\n /**\r\n * Subscribe on event.\r\n * When toolbar block settings is closed but block deletion is not confirmed,\r\n * then reset confirmation state\r\n */\r\n this.api.events.on('block-settings-closed', this.resetConfirmation);\r\n }\r\n else {\r\n /**\r\n * Unsubscribe from block-settings closing event\r\n */\r\n this.api.events.off('block-settings-closed', this.resetConfirmation);\r\n this.api.blocks.delete();\r\n }\r\n }\r\n /**\r\n * change tune state\r\n */\r\n setConfirmation(state) {\r\n this.needConfirmation = state;\r\n this.nodes.button.classList.add(this.CSS.buttonConfirm);\r\n }\r\n}\r\n","export default class MoveUpTune {\r\n /**\r\n * MoveUpTune constructor\r\n *\r\n * @param {Object} api\r\n */\r\n constructor({ api }) {\r\n /**\r\n * Styles\r\n * @type {{wrapper: string}}\r\n */\r\n this.CSS = {\r\n button: 'ce-settings__button',\r\n wrapper: 'ce-settings-move-up',\r\n btnDisabled: 'ce-settings-move-up--disabled',\r\n };\r\n this.api = api;\r\n }\r\n /**\r\n * Create \"MoveUp\" button and add click event listener\r\n * @returns [Element}\r\n */\r\n render() {\r\n const moveUpButton = $.make('div', [this.CSS.button, this.CSS.wrapper], {});\r\n moveUpButton.appendChild($.svg('arrow-up', 14, 14));\r\n if (this.api.blocks.getCurrentBlockIndex() === 0) {\r\n moveUpButton.classList.add(this.CSS.btnDisabled);\r\n }\r\n else {\r\n this.api.listener.on(moveUpButton, 'click', (event) => this.handleClick(event), false);\r\n }\r\n return moveUpButton;\r\n }\r\n /**\r\n * Move current block up\r\n * @param {MouseEvent} event\r\n */\r\n handleClick(event) {\r\n const currentBlockIndex = this.api.blocks.getCurrentBlockIndex();\r\n if (currentBlockIndex === 0) {\r\n return;\r\n }\r\n const currentBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex).html, previousBlockElement = this.api.blocks.getBlockByIndex(currentBlockIndex - 1).html;\r\n /**\r\n * Here is two cases:\r\n * - when previous block has negative offset and part of it is visible on window, then we scroll\r\n * by window's height and add offset which is mathematically difference between two blocks\r\n *\r\n * - when previous block is visible and has offset from the window,\r\n * than we scroll window to the difference between this offsets.\r\n */\r\n const currentBlockCoords = currentBlockElement.getBoundingClientRect(), previousBlockCoords = previousBlockElement.getBoundingClientRect();\r\n let scrollUpOffset;\r\n if (previousBlockCoords.top > 0) {\r\n scrollUpOffset = Math.abs(currentBlockCoords.top) - Math.abs(previousBlockCoords.top);\r\n }\r\n else {\r\n scrollUpOffset = window.innerHeight - Math.abs(currentBlockCoords.top) + Math.abs(previousBlockCoords.top);\r\n }\r\n window.scrollBy(0, -1 * scrollUpOffset);\r\n /** Change blocks positions */\r\n this.api.blocks.swap(currentBlockIndex, currentBlockIndex - 1);\r\n }\r\n}\r\n","/**\r\n * @class Block\r\n * @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool\r\n *\r\n * @property {Tool} tool — current block tool (Paragraph, for example)\r\n * @property {Object} CSS — block`s css classes\r\n *\r\n */\r\n\r\n/** Import default tunes */\r\nimport MoveUpTune from './block-tunes/block-tune-move-up';\r\nimport DeleteTune from './block-tunes/block-tune-delete';\r\n\r\n/**\r\n * @classdesc Abstract Block class that contains Block information, Tool name and Tool class instance\r\n *\r\n * @property tool - Tool instance\r\n * @property html - Returns HTML content of plugin\r\n * @property wrapper - Div element that wraps block content with Tool's content. Has `ce-block` CSS class\r\n * @property contentNode - Div element that wraps Tool's content. Has `ce-block__content` CSS class\r\n * @property pluginsContent - HTML content that returns by Tool's render function\r\n */\r\nexport default class Block {\r\n /**\r\n * @constructor\r\n * @param {String} toolName - Tool name that passed on initialization\r\n * @param {Object} toolInstance — passed Tool`s instance that rendered the Block\r\n * @param {Object} settings - default settings\r\n * @param {Object} apiMethods - Editor API\r\n */\r\n constructor(toolName, toolInstance, settings, apiMethods) {\r\n this.name = toolName;\r\n this.tool = toolInstance;\r\n this.settings = settings;\r\n this.api = apiMethods;\r\n this._html = this.compose();\r\n\r\n /**\r\n * @type {IBlockTune[]}\r\n */\r\n this.tunes = this.makeTunes();\r\n }\r\n\r\n /**\r\n * CSS classes for the Block\r\n * @return {{wrapper: string, content: string}}\r\n */\r\n static get CSS() {\r\n return {\r\n wrapper: 'ce-block',\r\n content: 'ce-block__content',\r\n selected: 'ce-block--selected'\r\n };\r\n }\r\n\r\n /**\r\n * Make default Block wrappers and put Tool`s content there\r\n * @returns {HTMLDivElement}\r\n */\r\n compose() {\r\n this.wrapper = $.make('div', Block.CSS.wrapper);\r\n this.contentNode = $.make('div', Block.CSS.content);\r\n this.pluginsContent = this.tool.render();\r\n\r\n this.contentNode.appendChild(this.pluginsContent);\r\n this.wrapper.appendChild(this.contentNode);\r\n\r\n return this.wrapper;\r\n }\r\n\r\n /**\r\n * Calls Tool's method\r\n *\r\n * Method checks tool property {MethodName}. Fires method with passes params If it is instance of Function\r\n *\r\n * @param {String} methodName\r\n * @param {Object} params\r\n */\r\n call(methodName, params) {\r\n /**\r\n * call Tool's method with the instance context\r\n */\r\n if (this.tool[methodName] && this.tool[methodName] instanceof Function) {\r\n this.tool[methodName].call(this.tool, params);\r\n }\r\n }\r\n\r\n /**\r\n * Get Block`s HTML\r\n * @returns {HTMLElement}\r\n */\r\n get html() {\r\n return this._html;\r\n }\r\n\r\n /**\r\n * Get Block's JSON data\r\n * @return {Object}\r\n */\r\n get data() {\r\n return this.save();\r\n }\r\n\r\n /**\r\n * is block mergeable\r\n * We plugin have merge function then we call it mergable\r\n * @return {boolean}\r\n */\r\n get mergeable() {\r\n return typeof this.tool.merge === 'function';\r\n }\r\n\r\n /**\r\n * Call plugins merge method\r\n * @param {Object} data\r\n */\r\n mergeWith(data) {\r\n return Promise.resolve()\r\n .then(() => {\r\n this.tool.merge(data);\r\n });\r\n }\r\n /**\r\n * Extracts data from Block\r\n * Groups Tool's save processing time\r\n * @return {Object}\r\n */\r\n save() {\r\n let extractedBlock = this.tool.save(this.pluginsContent);\r\n\r\n /** Measuring execution time*/\r\n let measuringStart = window.performance.now(),\r\n measuringEnd;\r\n\r\n return Promise.resolve(extractedBlock)\r\n .then((finishedExtraction) => {\r\n /** measure promise execution */\r\n measuringEnd = window.performance.now();\r\n\r\n return {\r\n tool: this.name,\r\n data: finishedExtraction,\r\n time : measuringEnd - measuringStart\r\n };\r\n })\r\n .catch(function (error) {\r\n _.log(`Saving proccess for ${this.tool.name} tool failed due to the ${error}`, 'log', 'red');\r\n });\r\n }\r\n\r\n /**\r\n * Uses Tool's validation method to check the correctness of output data\r\n * Tool's validation method is optional\r\n *\r\n * @description Method also can return data if it passed the validation\r\n *\r\n * @param {Object} data\r\n * @returns {Boolean|Object} valid\r\n */\r\n validateData(data) {\r\n let isValid = true;\r\n\r\n if (this.tool.validate instanceof Function) {\r\n isValid = this.tool.validate(data);\r\n }\r\n\r\n if (!isValid) {\r\n return false;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Make an array with default settings\r\n * Each block has default tune instance that have states\r\n * @return {IBlockTune[]}\r\n */\r\n makeTunes() {\r\n let tunesList = [MoveUpTune, DeleteTune];\r\n\r\n // Pluck tunes list and return tune instances with passed Editor API and settings\r\n return tunesList.map( (tune) => {\r\n return new tune({\r\n api: this.api,\r\n settings: this.settings,\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Enumerates initialized tunes and returns fragment that can be appended to the toolbars area\r\n * @return {DocumentFragment}\r\n */\r\n renderTunes() {\r\n let tunesElement = document.createDocumentFragment();\r\n\r\n this.tunes.forEach( tune => {\r\n $.append(tunesElement, tune.render());\r\n });\r\n\r\n return tunesElement;\r\n }\r\n\r\n /**\r\n * Check block for emptiness\r\n * @return {Boolean}\r\n */\r\n get isEmpty() {\r\n /**\r\n * Allow Tool to represent decorative contentless blocks: for example \"* * *\"-tool\r\n * That Tools are not empty\r\n */\r\n if (this.tool.contentless) {\r\n return false;\r\n }\r\n\r\n let emptyText = $.isEmpty(this.pluginsContent),\r\n emptyMedia = !this.hasMedia;\r\n\r\n return emptyText && emptyMedia;\r\n }\r\n\r\n /**\r\n * Check if block has a media content such as images, iframes and other\r\n * @return {Boolean}\r\n */\r\n get hasMedia() {\r\n /**\r\n * This tags represents media-content\r\n * @type {string[]}\r\n */\r\n const mediaTags = [\r\n 'img',\r\n 'iframe',\r\n 'video',\r\n 'audio',\r\n 'source',\r\n 'input',\r\n 'textarea',\r\n 'twitterwidget'\r\n ];\r\n\r\n return !!this._html.querySelector(mediaTags.join(','));\r\n }\r\n\r\n /**\r\n * Set selected state\r\n * @param {Boolean} state - 'true' to select, 'false' to remove selection\r\n */\r\n set selected(state) {\r\n /**\r\n * We don't need to mark Block as Selected when it is not empty\r\n */\r\n if (state === true && !this.isEmpty) {\r\n this._html.classList.add(Block.CSS.selected);\r\n } else {\r\n this._html.classList.remove(Block.CSS.selected);\r\n }\r\n }\r\n}\r\n","/**\r\n * DOM manipulations helper\r\n */\r\nexport default class Dom {\r\n /**\r\n * Check if passed tag has no closed tag\r\n * @param {Element} tag\r\n * @return {Boolean}\r\n */\r\n static isSingleTag(tag) {\r\n return tag.tagName && ['AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'].includes(tag.tagName);\r\n };\r\n\r\n\r\n /**\r\n * Helper for making Elements with classname and attributes\r\n *\r\n * @param {string} tagName - new Element tag name\r\n * @param {array|string} classNames - list or name of CSS classname(s)\r\n * @param {Object} attributes - any attributes\r\n * @return {Element}\r\n */\r\n static make(tagName, classNames = null, attributes = {}) {\r\n let el = document.createElement(tagName);\r\n\r\n if ( Array.isArray(classNames) ) {\r\n el.classList.add(...classNames);\r\n } else if( classNames ) {\r\n el.classList.add(classNames);\r\n }\r\n\r\n for (let attrName in attributes) {\r\n el[attrName] = attributes[attrName];\r\n }\r\n\r\n return el;\r\n }\r\n\r\n /**\r\n * Creates Text Node with the passed content\r\n * @param {String} content - text content\r\n * @return {Text}\r\n */\r\n static text(content) {\r\n return document.createTextNode(content);\r\n }\r\n\r\n /**\r\n * Creates SVG icon linked to the sprite\r\n * @param {string} name - name (id) of icon from sprite\r\n * @param {number} width\r\n * @param {number} height\r\n * @return {SVGElement}\r\n */\r\n static svg(name, width = 14, height = 14) {\r\n let icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n\r\n icon.classList.add('icon', 'icon--' + name);\r\n icon.setAttribute('width', width + 'px');\r\n icon.setAttribute('height', height + 'px');\r\n icon.innerHTML = ``;\r\n\r\n return icon;\r\n }\r\n\r\n /**\r\n * Append one or several elements to the parent\r\n *\r\n * @param {Element} parent - where to append\r\n * @param {Element|Element[]} - element ore elements list\r\n */\r\n static append(parent, elements) {\r\n if ( Array.isArray(elements) ) {\r\n elements.forEach( el => parent.appendChild(el) );\r\n } else {\r\n parent.appendChild(elements);\r\n }\r\n }\r\n\r\n /**\r\n * Swap two elements in parent\r\n * @param {HTMLElement} el1 - from\r\n * @param {HTMLElement} el2 - to\r\n */\r\n static swap(el1, el2) {\r\n // create marker element and insert it where el1 is\r\n const temp = document.createElement('div'),\r\n parent = el1.parentNode;\r\n\r\n parent.insertBefore(temp, el1);\r\n\r\n // move el1 to right before el2\r\n parent.insertBefore(el1, el2);\r\n\r\n // move el2 to right before where el1 used to be\r\n parent.insertBefore(el2, temp);\r\n\r\n // remove temporary marker node\r\n parent.removeChild(temp);\r\n }\r\n\r\n /**\r\n * Selector Decorator\r\n *\r\n * Returns first match\r\n *\r\n * @param {Element} el - element we searching inside. Default - DOM Document\r\n * @param {String} selector - searching string\r\n *\r\n * @returns {Element}\r\n */\r\n static find(el = document, selector) {\r\n return el.querySelector(selector);\r\n }\r\n\r\n /**\r\n * Selector Decorator.\r\n *\r\n * Returns all matches\r\n *\r\n * @param {Element} el - element we searching inside. Default - DOM Document\r\n * @param {String} selector - searching string\r\n * @returns {NodeList}\r\n */\r\n static findAll(el = document, selector) {\r\n return el.querySelectorAll(selector);\r\n }\r\n\r\n /**\r\n * Search for deepest node which is Leaf.\r\n * Leaf is the vertex that doesn't have any child nodes\r\n *\r\n * @description Method recursively goes throw the all Node until it finds the Leaf\r\n *\r\n * @param {Node} node - root Node. From this vertex we start Deep-first search {@link https://en.wikipedia.org/wiki/Depth-first_search}\r\n * @param {Boolean} atLast - find last text node\r\n * @return {Node} - it can be text Node or Element Node, so that caret will able to work with it\r\n */\r\n static getDeepestNode(node, atLast = false) {\r\n /**\r\n * Current function have two directions:\r\n * - starts from first child and every time gets first or nextSibling in special cases\r\n * - starts from last child and gets last or previousSibling\r\n * @type {string}\r\n */\r\n let child = atLast ? 'lastChild' : 'firstChild',\r\n sibling = atLast ? 'previousSibling' : 'nextSibling';\r\n\r\n if (node && node.nodeType === Node.ELEMENT_NODE && node[child]) {\r\n let nodeChild = node[child];\r\n\r\n /**\r\n * special case when child is single tag that can't contain any content\r\n */\r\n if (Dom.isSingleTag(nodeChild)) {\r\n /**\r\n * 1) We need to check the next sibling. If it is Node Element then continue searching for deepest\r\n * from sibling\r\n *\r\n * 2) If single tag's next sibling is null, then go back to parent and check his sibling\r\n * In case of Node Element continue searching\r\n *\r\n * 3) If none of conditions above happened return parent Node Element\r\n */\r\n if (nodeChild[sibling]) {\r\n nodeChild = nodeChild[sibling];\r\n } else if (nodeChild.parentNode[sibling]) {\r\n nodeChild = nodeChild.parentNode[sibling];\r\n } else {\r\n return nodeChild.parentNode;\r\n }\r\n }\r\n\r\n return this.getDeepestNode(nodeChild, atLast);\r\n }\r\n\r\n return node;\r\n }\r\n\r\n /**\r\n * Check if object is DOM node\r\n *\r\n * @param {Object} node\r\n * @returns {boolean}\r\n */\r\n static isElement(node) {\r\n return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE;\r\n }\r\n\r\n /**\r\n * Checks target if it is native input\r\n * @param {Element|String} target - HTML element or string\r\n * @return {Boolean}\r\n */\r\n static isNativeInput(target) {\r\n let nativeInputs = [\r\n 'INPUT',\r\n 'TEXTAREA'\r\n ];\r\n\r\n return target ? nativeInputs.includes(target.tagName) : false;\r\n }\r\n\r\n /**\r\n * Checks node if it is empty\r\n *\r\n * @description Method checks simple Node without any childs for emptiness\r\n * If you have Node with 2 or more children id depth, you better use {@link Dom#isEmpty} method\r\n *\r\n * @param {Node} node\r\n * @return {Boolean} true if it is empty\r\n */\r\n static isNodeEmpty(node) {\r\n let nodeText;\r\n\r\n if ( this.isElement(node) && this.isNativeInput(node) ) {\r\n nodeText = node.value;\r\n } else {\r\n nodeText = node.textContent.replace('\\u200B', '');\r\n }\r\n\r\n return nodeText.trim().length === 0;\r\n }\r\n\r\n /**\r\n * checks node if it is doesn't have any child nodes\r\n * @param {Node} node\r\n * @return {boolean}\r\n */\r\n static isLeaf(node) {\r\n if (!node) {\r\n return false;\r\n }\r\n\r\n return node.childNodes.length === 0;\r\n }\r\n\r\n /**\r\n * breadth-first search (BFS)\r\n * {@link https://en.wikipedia.org/wiki/Breadth-first_search}\r\n *\r\n * @description Pushes to stack all DOM leafs and checks for emptiness\r\n *\r\n * @param {Node} node\r\n * @return {boolean}\r\n */\r\n static isEmpty(node) {\r\n let treeWalker = [],\r\n leafs = [];\r\n\r\n if (!node) {\r\n return true;\r\n }\r\n\r\n if (!node.childNodes.length) {\r\n return this.isNodeEmpty(node);\r\n }\r\n\r\n treeWalker.push(node.firstChild);\r\n\r\n while ( treeWalker.length > 0 ) {\r\n node = treeWalker.shift();\r\n\r\n if (!node) continue;\r\n\r\n if ( this.isLeaf(node) ) {\r\n leafs.push(node);\r\n } else {\r\n treeWalker.push(node.firstChild);\r\n }\r\n\r\n while ( node && node.nextSibling ) {\r\n node = node.nextSibling;\r\n\r\n if (!node) continue;\r\n\r\n treeWalker.push(node);\r\n }\r\n\r\n /**\r\n * If one of childs is not empty, checked Node is not empty too\r\n */\r\n if (node && !this.isNodeEmpty(node)) {\r\n return false;\r\n }\r\n }\r\n\r\n return leafs.every( leaf => this.isNodeEmpty(leaf) );\r\n }\r\n};\r\n","/**\r\n * Bold Tool\r\n *\r\n * Inline Toolbar Tool\r\n *\r\n * Makes selected text bolder\r\n */\r\nexport default class BoldInlineTool {\r\n constructor(api) {\r\n /**\r\n * Native Document's command that uses for Bold\r\n */\r\n this.commandName = 'bold';\r\n /**\r\n * Styles\r\n */\r\n this.CSS = {\r\n button: 'ce-inline-tool',\r\n buttonActive: 'ce-inline-tool--active',\r\n buttonModifier: 'ce-inline-tool--bold',\r\n };\r\n /**\r\n * Elements\r\n */\r\n this.nodes = {\r\n button: null,\r\n };\r\n console.log('Bold Inline Tool is ready');\r\n }\r\n /**\r\n * Create button for Inline Toolbar\r\n */\r\n render() {\r\n this.nodes.button = document.createElement('button');\r\n this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);\r\n this.nodes.button.appendChild($.svg('bold', 13, 15));\r\n return this.nodes.button;\r\n }\r\n /**\r\n * Wrap range with tag\r\n * @param {Range} range\r\n */\r\n surround(range) {\r\n document.execCommand(this.commandName);\r\n }\r\n /**\r\n * Check selection and set activated state to button if there are tag\r\n * @param {Selection} selection\r\n */\r\n checkState(selection) {\r\n const isActive = document.queryCommandState(this.commandName);\r\n this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);\r\n return isActive;\r\n }\r\n}\r\n","/**\r\n * Italic Tool\r\n *\r\n * Inline Toolbar Tool\r\n *\r\n * Style selected text with italic\r\n */\r\nexport default class ItalicInlineTool {\r\n constructor(api) {\r\n /**\r\n * Native Document's command that uses for Italic\r\n */\r\n this.commandName = 'italic';\r\n /**\r\n * Styles\r\n */\r\n this.CSS = {\r\n button: 'ce-inline-tool',\r\n buttonActive: 'ce-inline-tool--active',\r\n buttonModifier: 'ce-inline-tool--italic',\r\n };\r\n /**\r\n * Elements\r\n */\r\n this.nodes = {\r\n button: null,\r\n };\r\n console.log('Italic Inline Tool is ready');\r\n }\r\n /**\r\n * Create button for Inline Toolbar\r\n */\r\n render() {\r\n this.nodes.button = document.createElement('button');\r\n this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);\r\n this.nodes.button.appendChild($.svg('italic', 6, 15));\r\n return this.nodes.button;\r\n }\r\n /**\r\n * Wrap range with tag\r\n * @param {Range} range\r\n */\r\n surround(range) {\r\n document.execCommand(this.commandName);\r\n }\r\n /**\r\n * Check selection and set activated state to button if there are tag\r\n * @param {Selection} selection\r\n */\r\n checkState(selection) {\r\n const isActive = document.queryCommandState(this.commandName);\r\n this.nodes.button.classList.toggle(this.CSS.buttonActive, isActive);\r\n return isActive;\r\n }\r\n}\r\n","import Selection from '../selection';\r\n/**\r\n * Link Tool\r\n *\r\n * Inline Toolbar Tool\r\n *\r\n * Wrap selected text with tag\r\n */\r\nexport default class LinkInlineTool {\r\n /**\r\n * @param {object} api - CodeX Editor API\r\n * @param {object} api.toolbar - Inline Toolbar API\r\n */\r\n constructor(api) {\r\n /**\r\n * Native Document's commands for link/unlink\r\n */\r\n this.commandLink = 'createLink';\r\n this.commandUnlink = 'unlink';\r\n /**\r\n * Enter key code\r\n */\r\n this.ENTER_KEY = 13;\r\n /**\r\n * Styles\r\n */\r\n this.CSS = {\r\n button: 'ce-inline-tool',\r\n buttonActive: 'ce-inline-tool--active',\r\n buttonModifier: 'ce-inline-tool--link',\r\n buttonUnlink: 'ce-inline-tool--unlink',\r\n input: 'ce-inline-tool-input',\r\n inputShowed: 'ce-inline-tool-input--showed',\r\n };\r\n /**\r\n * Elements\r\n */\r\n this.nodes = {\r\n button: null,\r\n input: null,\r\n };\r\n /**\r\n * Input opening state\r\n */\r\n this.inputOpened = false;\r\n this.inlineToolbar = api.toolbar;\r\n this.selection = new Selection();\r\n }\r\n /**\r\n * Create button for Inline Toolbar\r\n */\r\n render() {\r\n this.nodes.button = document.createElement('button');\r\n this.nodes.button.classList.add(this.CSS.button, this.CSS.buttonModifier);\r\n this.nodes.button.appendChild($.svg('link', 15, 14));\r\n this.nodes.button.appendChild($.svg('unlink', 16, 18));\r\n return this.nodes.button;\r\n }\r\n /**\r\n * Input for the link\r\n */\r\n renderActions() {\r\n this.nodes.input = document.createElement('input');\r\n this.nodes.input.placeholder = 'Add a link';\r\n this.nodes.input.classList.add(this.CSS.input);\r\n this.nodes.input.addEventListener('keydown', (event) => {\r\n if (event.keyCode === this.ENTER_KEY) {\r\n this.enterPressed(event);\r\n }\r\n });\r\n return this.nodes.input;\r\n }\r\n /**\r\n * Handle clicks on the Inline Toolbar icon\r\n * @param {Range} range\r\n */\r\n surround(range) {\r\n /**\r\n * Range will be null when user makes second click on the 'link icon' to close opened input\r\n */\r\n if (range) {\r\n /**\r\n * Save selection before change focus to the input\r\n */\r\n this.selection.save();\r\n const parentAnchor = this.selection.findParentTag('A');\r\n /**\r\n * Unlink icon pressed\r\n */\r\n if (parentAnchor) {\r\n this.selection.expandToTag(parentAnchor);\r\n this.unlink();\r\n this.closeActions();\r\n this.checkState();\r\n this.inlineToolbar.close();\r\n return;\r\n }\r\n }\r\n this.toggleActions();\r\n }\r\n /**\r\n * Check selection and set activated state to button if there are tag\r\n * @param {Selection} selection\r\n */\r\n checkState(selection) {\r\n const anchorTag = this.selection.findParentTag('A');\r\n if (anchorTag) {\r\n this.nodes.button.classList.add(this.CSS.buttonUnlink);\r\n this.nodes.button.classList.add(this.CSS.buttonActive);\r\n this.openActions();\r\n /**\r\n * Fill input value with link href\r\n */\r\n const hrefAttr = anchorTag.getAttribute('href');\r\n this.nodes.input.value = hrefAttr !== 'null' ? hrefAttr : '';\r\n this.selection.save();\r\n }\r\n else {\r\n this.nodes.button.classList.remove(this.CSS.buttonUnlink);\r\n this.nodes.button.classList.remove(this.CSS.buttonActive);\r\n }\r\n return !!anchorTag;\r\n }\r\n /**\r\n * Function called with Inline Toolbar closing\r\n */\r\n clear() {\r\n this.closeActions();\r\n }\r\n toggleActions() {\r\n if (!this.inputOpened) {\r\n this.openActions(true);\r\n }\r\n else {\r\n this.closeActions(false);\r\n }\r\n }\r\n /**\r\n * @param {boolean} needFocus - on link creation we need to focus input. On editing - nope.\r\n */\r\n openActions(needFocus = false) {\r\n this.nodes.input.classList.add(this.CSS.inputShowed);\r\n if (needFocus) {\r\n this.nodes.input.focus();\r\n }\r\n this.inputOpened = true;\r\n }\r\n /**\r\n * Close input\r\n * @param {boolean} clearSavedSelection — we don't need to clear saved selection\r\n * on toggle-clicks on the icon of opened Toolbar\r\n */\r\n closeActions(clearSavedSelection = true) {\r\n this.nodes.input.classList.remove(this.CSS.inputShowed);\r\n this.nodes.input.value = '';\r\n if (clearSavedSelection) {\r\n this.selection.clearSaved();\r\n }\r\n this.inputOpened = false;\r\n }\r\n /**\r\n * Enter pressed on input\r\n * @param {KeyboardEvent} event\r\n */\r\n enterPressed(event) {\r\n let value = this.nodes.input.value || '';\r\n if (!value.trim()) {\r\n this.selection.restore();\r\n this.unlink();\r\n event.preventDefault();\r\n this.closeActions();\r\n }\r\n if (!this.validateURL(value)) {\r\n /**\r\n * @todo show notification 'Incorrect Link'\r\n */\r\n _.log('Incorrect Link pasted', 'warn', value);\r\n return;\r\n }\r\n value = this.prepareLink(value);\r\n this.selection.restore();\r\n this.insertLink(value);\r\n /**\r\n * Preventing events that will be able to happen\r\n */\r\n event.preventDefault();\r\n event.stopPropagation();\r\n event.stopImmediatePropagation();\r\n this.closeActions();\r\n this.inlineToolbar.close();\r\n this.checkState();\r\n }\r\n /**\r\n * Detects if passed string is URL\r\n * @param {string} str\r\n * @return {Boolean}\r\n */\r\n validateURL(str) {\r\n /**\r\n * Don't allow spaces\r\n */\r\n return !/\\s/.test(str);\r\n }\r\n /**\r\n * Process link before injection\r\n * - sanitize\r\n * - add protocol for links like 'google.com'\r\n * @param {string} link - raw user input\r\n */\r\n prepareLink(link) {\r\n link = link.trim();\r\n link = this.addProtocol(link);\r\n return link;\r\n }\r\n /**\r\n * Add 'http' protocol to the links like 'vc.ru', 'google.com'\r\n * @param {String} link\r\n */\r\n addProtocol(link) {\r\n /**\r\n * If protocol already exists, do nothing\r\n */\r\n if (/^(\\w+):\\/\\//.test(link)) {\r\n return link;\r\n }\r\n /**\r\n * We need to add missed HTTP protocol to the link, but skip 2 cases:\r\n * 1) Internal links like \"/general\"\r\n * 2) Anchors looks like \"#results\"\r\n * 3) Protocol-relative URLs like \"//google.com\"\r\n */\r\n const isInternal = /^\\/[^\\/\\s]/.test(link), isAnchor = link.substring(0, 1) === '#', isProtocolRelative = /^\\/\\/[^\\/\\s]/.test(link);\r\n if (!isInternal && !isAnchor && !isProtocolRelative) {\r\n link = 'http://' + link;\r\n }\r\n return link;\r\n }\r\n /**\r\n * Inserts tag with \"href\"\r\n * @param {string} link - \"href\" value\r\n */\r\n insertLink(link) {\r\n /**\r\n * Edit all link, not selected part\r\n */\r\n const anchorTag = this.selection.findParentTag('A');\r\n if (anchorTag) {\r\n this.selection.expandToTag(anchorTag);\r\n }\r\n document.execCommand(this.commandLink, false, link);\r\n }\r\n /**\r\n * Removes tag\r\n */\r\n unlink() {\r\n document.execCommand(this.commandUnlink);\r\n }\r\n}\r\n","var map = {\n\t\"./_anchors\": \"./src/components/modules/_anchors.js\",\n\t\"./_anchors.js\": \"./src/components/modules/_anchors.js\",\n\t\"./_callbacks\": \"./src/components/modules/_callbacks.js\",\n\t\"./_callbacks.js\": \"./src/components/modules/_callbacks.js\",\n\t\"./_caret\": \"./src/components/modules/_caret.js\",\n\t\"./_caret.js\": \"./src/components/modules/_caret.js\",\n\t\"./_content\": \"./src/components/modules/_content.js\",\n\t\"./_content.js\": \"./src/components/modules/_content.js\",\n\t\"./_destroyer\": \"./src/components/modules/_destroyer.js\",\n\t\"./_destroyer.js\": \"./src/components/modules/_destroyer.js\",\n\t\"./_notifications\": \"./src/components/modules/_notifications.js\",\n\t\"./_notifications.js\": \"./src/components/modules/_notifications.js\",\n\t\"./_parser\": \"./src/components/modules/_parser.js\",\n\t\"./_parser.js\": \"./src/components/modules/_parser.js\",\n\t\"./_paste\": \"./src/components/modules/_paste.js\",\n\t\"./_paste.js\": \"./src/components/modules/_paste.js\",\n\t\"./_transport\": \"./src/components/modules/_transport.js\",\n\t\"./_transport.js\": \"./src/components/modules/_transport.js\",\n\t\"./api\": \"./src/components/modules/api.ts\",\n\t\"./api-blocks\": \"./src/components/modules/api-blocks.ts\",\n\t\"./api-blocks.ts\": \"./src/components/modules/api-blocks.ts\",\n\t\"./api-events\": \"./src/components/modules/api-events.ts\",\n\t\"./api-events.ts\": \"./src/components/modules/api-events.ts\",\n\t\"./api-listener\": \"./src/components/modules/api-listener.ts\",\n\t\"./api-listener.ts\": \"./src/components/modules/api-listener.ts\",\n\t\"./api-sanitizer\": \"./src/components/modules/api-sanitizer.ts\",\n\t\"./api-sanitizer.ts\": \"./src/components/modules/api-sanitizer.ts\",\n\t\"./api-saver\": \"./src/components/modules/api-saver.ts\",\n\t\"./api-saver.ts\": \"./src/components/modules/api-saver.ts\",\n\t\"./api-selection\": \"./src/components/modules/api-selection.ts\",\n\t\"./api-selection.ts\": \"./src/components/modules/api-selection.ts\",\n\t\"./api-toolbar\": \"./src/components/modules/api-toolbar.ts\",\n\t\"./api-toolbar.ts\": \"./src/components/modules/api-toolbar.ts\",\n\t\"./api.ts\": \"./src/components/modules/api.ts\",\n\t\"./block-events\": \"./src/components/modules/block-events.ts\",\n\t\"./block-events.ts\": \"./src/components/modules/block-events.ts\",\n\t\"./blockManager\": \"./src/components/modules/blockManager.js\",\n\t\"./blockManager.js\": \"./src/components/modules/blockManager.js\",\n\t\"./caret\": \"./src/components/modules/caret.js\",\n\t\"./caret.js\": \"./src/components/modules/caret.js\",\n\t\"./events\": \"./src/components/modules/events.js\",\n\t\"./events.js\": \"./src/components/modules/events.js\",\n\t\"./listeners\": \"./src/components/modules/listeners.js\",\n\t\"./listeners.js\": \"./src/components/modules/listeners.js\",\n\t\"./renderer\": \"./src/components/modules/renderer.js\",\n\t\"./renderer.js\": \"./src/components/modules/renderer.js\",\n\t\"./sanitizer\": \"./src/components/modules/sanitizer.js\",\n\t\"./sanitizer.js\": \"./src/components/modules/sanitizer.js\",\n\t\"./saver\": \"./src/components/modules/saver.js\",\n\t\"./saver.js\": \"./src/components/modules/saver.js\",\n\t\"./toolbar\": \"./src/components/modules/toolbar.js\",\n\t\"./toolbar-blockSettings\": \"./src/components/modules/toolbar-blockSettings.js\",\n\t\"./toolbar-blockSettings.js\": \"./src/components/modules/toolbar-blockSettings.js\",\n\t\"./toolbar-inline\": \"./src/components/modules/toolbar-inline.ts\",\n\t\"./toolbar-inline.ts\": \"./src/components/modules/toolbar-inline.ts\",\n\t\"./toolbar-toolbox\": \"./src/components/modules/toolbar-toolbox.js\",\n\t\"./toolbar-toolbox.js\": \"./src/components/modules/toolbar-toolbox.js\",\n\t\"./toolbar.js\": \"./src/components/modules/toolbar.js\",\n\t\"./toolbar/inline\": \"./src/components/modules/toolbar/inline.js\",\n\t\"./toolbar/inline.js\": \"./src/components/modules/toolbar/inline.js\",\n\t\"./toolbar/settings\": \"./src/components/modules/toolbar/settings.js\",\n\t\"./toolbar/settings.js\": \"./src/components/modules/toolbar/settings.js\",\n\t\"./toolbar/toolbar\": \"./src/components/modules/toolbar/toolbar.js\",\n\t\"./toolbar/toolbar.js\": \"./src/components/modules/toolbar/toolbar.js\",\n\t\"./toolbar/toolbox\": \"./src/components/modules/toolbar/toolbox.js\",\n\t\"./toolbar/toolbox.js\": \"./src/components/modules/toolbar/toolbox.js\",\n\t\"./tools\": \"./src/components/modules/tools.js\",\n\t\"./tools.js\": \"./src/components/modules/tools.js\",\n\t\"./ui\": \"./src/components/modules/ui.js\",\n\t\"./ui.js\": \"./src/components/modules/ui.js\"\n};\n\n\nfunction webpackContext(req) {\n\tvar id = webpackContextResolve(req);\n\treturn __webpack_require__(id);\n}\nfunction webpackContextResolve(req) {\n\tvar id = map[req];\n\tif(!(id + 1)) { // check for number or string\n\t\tvar e = new Error(\"Cannot find module '\" + req + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\treturn id;\n}\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = \"./src/components/modules sync recursive ^\\\\.\\\\/.*$\";","/**\r\n * Codex Editor Anchors module\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = function (anchors) {\n let editor = codex.editor;\r\n\r\n anchors.input = null;\r\n anchors.currentNode = null;\r\n\r\n anchors.settingsOpened = function (currentBlock) {\n anchors.currentNode = currentBlock;\r\n anchors.input.value = anchors.currentNode.dataset.anchor || '';\n };\r\n\r\n anchors.anchorChanged = function (e) {\n var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);\r\n\r\n anchors.currentNode.dataset.anchor = newAnchor;\r\n\r\n if (newAnchor.trim() !== '') {\n anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n } else {\n anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);\n }\n };\r\n\r\n anchors.keyDownOnAnchorInput = function (e) {\n if (e.keyCode == editor.core.keys.ENTER) {\n e.preventDefault();\r\n e.stopPropagation();\r\n\r\n e.target.blur();\r\n editor.toolbar.settings.close();\n }\n };\r\n\r\n anchors.keyUpOnAnchorInput = function (e) {\n if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {\n e.stopPropagation();\n }\n };\r\n\r\n anchors.rusToTranslit = function (string) {\n var ru = [\r\n 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й',\r\n 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф',\r\n 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'\r\n ],\r\n en = [\r\n 'A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y',\r\n 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F',\r\n 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya'\r\n ];\r\n\r\n for (var i = 0; i < ru.length; i++) {\n string = string.split(ru[i]).join(en[i]);\r\n string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());\n }\r\n\r\n string = string.replace(/[^0-9a-zA-Z_]+/g, '-');\r\n\r\n return string;\n };\r\n\r\n return anchors;\n}({});","/**\r\n * @module Codex Editor Callbacks module\r\n * @description Module works with editor added Elements\r\n *\r\n * @author Codex Team\r\n * @version 1.4.0\r\n */\r\n\r\nmodule.exports = (function (callbacks) {\n let editor = codex.editor;\r\n\r\n /**\r\n * used by UI module\r\n * @description Routes all keydowns on document\r\n * @param {Object} event\r\n */\r\n callbacks.globalKeydown = function (event) {\n switch (event.keyCode) {\n case editor.core.keys.ENTER : enterKeyPressed_(event); break;\n }\n };\r\n\r\n /**\r\n * used by UI module\r\n * @description Routes all keydowns on redactors area\r\n * @param {Object} event\r\n */\r\n callbacks.redactorKeyDown = function (event) {\n switch (event.keyCode) {\n case editor.core.keys.TAB : tabKeyPressedOnRedactorsZone_(event); break;\r\n case editor.core.keys.ENTER : enterKeyPressedOnRedactorsZone_(event); break;\r\n case editor.core.keys.ESC : escapeKeyPressedOnRedactorsZone_(event); break;\r\n default : defaultKeyPressedOnRedactorsZone_(event); break;\n }\n };\r\n\r\n /**\r\n * used by UI module\r\n * @description Routes all keyup events\r\n * @param {Object} event\r\n */\r\n callbacks.globalKeyup = function (event) {\n switch (event.keyCode) {\n case editor.core.keys.UP :\r\n case editor.core.keys.LEFT :\r\n case editor.core.keys.RIGHT :\r\n case editor.core.keys.DOWN : arrowKeyPressed_(event); break;\n }\n };\r\n\r\n /**\r\n * @param {Object} event\r\n * @private\r\n *\r\n * Handles behaviour when tab pressed\r\n * @description if Content is empty show toolbox (if it is closed) or leaf tools\r\n * uses Toolbars toolbox module to handle the situation\r\n */\r\n var tabKeyPressedOnRedactorsZone_ = function (event) {\n /**\r\n * Wait for solution. Would like to know the behaviour\r\n * @todo Add spaces\r\n */\r\n event.preventDefault();\r\n\r\n\r\n if (!editor.core.isBlockEmpty(editor.content.currentNode)) {\n return;\n }\r\n\r\n if ( !editor.toolbar.opened ) {\n editor.toolbar.open();\n }\r\n\r\n if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n editor.toolbar.toolbox.open();\n } else {\n editor.toolbar.toolbox.leaf();\n }\n };\r\n\r\n /**\r\n * Handles global EnterKey Press\r\n * @see enterPressedOnBlock_\r\n * @param {Object} event\r\n */\r\n var enterKeyPressed_ = function () {\n if (editor.content.editorAreaHightlighted) {\n /**\r\n * it means that we lose input index, saved index before is not correct\r\n * therefore we need to set caret when we insert new block\r\n */\r\n editor.caret.inputIndex = -1;\r\n\r\n enterPressedOnBlock_();\n }\n };\r\n\r\n /**\r\n * Callback for enter key pressing in first-level block area\r\n *\r\n * @param {Event} event\r\n * @private\r\n *\r\n * @description Inserts new block with initial type from settings\r\n */\r\n var enterPressedOnBlock_ = function () {\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\r\n\r\n editor.content.insertBlock({\r\n type : NEW_BLOCK_TYPE,\r\n block : editor.tools[NEW_BLOCK_TYPE].render()\r\n }, true );\r\n\r\n editor.toolbar.move();\r\n editor.toolbar.open();\n };\r\n\r\n\r\n /**\r\n * ENTER key handler\r\n *\r\n * @param {Object} event\r\n * @private\r\n *\r\n * @description Makes new block with initial type from settings\r\n */\r\n var enterKeyPressedOnRedactorsZone_ = function (event) {\n if (event.target.contentEditable == 'true') {\n /** Update input index */\r\n editor.caret.saveCurrentInputIndex();\n }\r\n\r\n var currentInputIndex = editor.caret.getCurrentInputIndex() || 0,\r\n workingNode = editor.content.currentNode,\r\n tool = workingNode.dataset.tool,\r\n isEnterPressedOnToolbar = editor.toolbar.opened &&\r\n editor.toolbar.current &&\r\n event.target == editor.state.inputs[currentInputIndex];\r\n\r\n /** The list of tools which needs the default browser behaviour */\r\n var enableLineBreaks = editor.tools[tool].enableLineBreaks;\r\n\r\n /** This type of block creates when enter is pressed */\r\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\r\n\r\n /**\r\n * When toolbar is opened, select tool instead of making new paragraph\r\n */\r\n if ( isEnterPressedOnToolbar ) {\n event.preventDefault();\r\n\r\n editor.toolbar.toolbox.toolClicked(event);\r\n\r\n editor.toolbar.close();\r\n\r\n /**\r\n * Stop other listeners callback executions\r\n */\r\n event.stopPropagation();\r\n event.stopImmediatePropagation();\r\n\r\n return;\n }\r\n\r\n /**\r\n * Allow paragraph lineBreaks with shift enter\r\n * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation\r\n */\r\n if ( event.shiftKey || enableLineBreaks ) {\n event.stopPropagation();\r\n event.stopImmediatePropagation();\r\n return;\n }\r\n\r\n var currentSelection = window.getSelection(),\r\n currentSelectedNode = currentSelection.anchorNode,\r\n caretAtTheEndOfText = editor.caret.position.atTheEnd(),\r\n isTextNodeHasParentBetweenContenteditable = false;\r\n\r\n /**\r\n * Allow making new

    in same block by SHIFT+ENTER and forbids to prevent default browser behaviour\r\n */\r\n if ( event.shiftKey && !enableLineBreaks ) {\n editor.callback.enterPressedOnBlock(editor.content.currentBlock, event);\r\n event.preventDefault();\r\n return;\n }\r\n\r\n /**\r\n * Workaround situation when caret at the Text node that has some wrapper Elements\r\n * Split block cant handle this.\r\n * We need to save default behavior\r\n */\r\n isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true';\r\n\r\n /**\r\n * Split blocks when input has several nodes and caret placed in textNode\r\n */\r\n if (\r\n currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT &&\r\n !isTextNodeHasParentBetweenContenteditable &&\r\n !caretAtTheEndOfText\r\n ) {\n event.preventDefault();\r\n\r\n editor.core.log('Splitting Text node...');\r\n\r\n editor.content.splitBlock(currentInputIndex);\r\n\r\n /** Show plus button when next input after split is empty*/\r\n if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) {\n editor.toolbar.showPlusButton();\n }\n } else {\n var islastNode = editor.content.isLastNode(currentSelectedNode);\r\n\r\n if ( islastNode && caretAtTheEndOfText ) {\n event.preventDefault();\r\n event.stopPropagation();\r\n event.stopImmediatePropagation();\r\n\r\n editor.core.log('ENTER clicked in last textNode. Create new BLOCK');\r\n\r\n editor.content.insertBlock({\r\n type: NEW_BLOCK_TYPE,\r\n block: editor.tools[NEW_BLOCK_TYPE].render()\r\n }, true);\r\n\r\n editor.toolbar.move();\r\n editor.toolbar.open();\r\n\r\n /** Show plus button with empty block */\r\n editor.toolbar.showPlusButton();\n }\n }\r\n\r\n /** get all inputs after new appending block */\r\n editor.ui.saveInputs();\n };\r\n\r\n /**\r\n * Escape behaviour\r\n * @param event\r\n * @private\r\n *\r\n * @description Closes toolbox and toolbar. Prevents default behaviour\r\n */\r\n var escapeKeyPressedOnRedactorsZone_ = function (event) {\n /** Close all toolbar */\r\n editor.toolbar.close();\r\n\r\n /** Close toolbox */\r\n editor.toolbar.toolbox.close();\r\n\r\n event.preventDefault();\n };\r\n\r\n /**\r\n * @param {Event} event\r\n * @private\r\n *\r\n * closes and moves toolbar\r\n */\r\n var arrowKeyPressed_ = function (event) {\n editor.content.workingNodeChanged();\r\n\r\n /* Closing toolbar */\r\n editor.toolbar.close();\r\n editor.toolbar.move();\n };\r\n\r\n /**\r\n * @private\r\n * @param {Event} event\r\n *\r\n * @description Closes all opened bars from toolbar.\r\n * If block is mark, clears highlightning\r\n */\r\n var defaultKeyPressedOnRedactorsZone_ = function () {\n editor.toolbar.close();\r\n\r\n if (!editor.toolbar.inline.actionsOpened) {\n editor.toolbar.inline.close();\r\n editor.content.clearMark();\n }\n };\r\n\r\n /**\r\n * Handler when clicked on redactors area\r\n *\r\n * @protected\r\n * @param event\r\n *\r\n * @description Detects clicked area. If it is first-level block area, marks as detected and\r\n * on next enter press will be inserted new block\r\n * Otherwise, save carets position (input index) and put caret to the editable zone.\r\n *\r\n * @see detectWhenClickedOnFirstLevelBlockArea_\r\n *\r\n */\r\n callbacks.redactorClicked = function (event) {\n detectWhenClickedOnFirstLevelBlockArea_();\r\n\r\n editor.content.workingNodeChanged(event.target);\r\n editor.ui.saveInputs();\r\n\r\n var selectedText = editor.toolbar.inline.getSelectionText(),\r\n firstLevelBlock;\r\n\r\n /** If selection range took off, then we hide inline toolbar */\r\n if (selectedText.length === 0) {\n editor.toolbar.inline.close();\n }\r\n\r\n /** Update current input index in memory when caret focused into existed input */\r\n if (event.target.contentEditable == 'true') {\n editor.caret.saveCurrentInputIndex();\n }\r\n\r\n if (editor.content.currentNode === null) {\n /**\r\n * If inputs in redactor does not exits, then we put input index 0 not -1\r\n */\r\n var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0;\r\n\r\n /** If we have any inputs */\r\n if (editor.state.inputs.length) {\n /** getting firstlevel parent of input */\r\n firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);\n }\r\n\r\n /** If input is empty, then we set caret to the last input */\r\n if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {\n editor.caret.setToBlock(indexOfLastInput);\n } else {\n /** Create new input when caret clicked in redactors area */\r\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\r\n\r\n editor.content.insertBlock({\r\n type : NEW_BLOCK_TYPE,\r\n block : editor.tools[NEW_BLOCK_TYPE].render()\r\n });\r\n\r\n /** If there is no inputs except inserted */\r\n if (editor.state.inputs.length === 1) {\n editor.caret.setToBlock(indexOfLastInput);\n } else {\n /** Set caret to this appended input */\r\n editor.caret.setToNextBlock(indexOfLastInput);\n }\n }\n } else {\n /** Close all panels */\r\n editor.toolbar.settings.close();\r\n editor.toolbar.toolbox.close();\n }\r\n\r\n /**\r\n * Move toolbar and open\r\n */\r\n editor.toolbar.move();\r\n editor.toolbar.open();\r\n\r\n var inputIsEmpty = !editor.content.currentNode.textContent.trim(),\r\n currentNodeType = editor.content.currentNode.dataset.tool,\r\n isInitialType = currentNodeType == editor.settings.initialBlockPlugin;\r\n\r\n\r\n /** Hide plus buttons */\r\n editor.toolbar.hidePlusButton();\r\n\r\n if (!inputIsEmpty) {\n /** Mark current block */\r\n editor.content.markBlock();\n }\r\n\r\n if ( isInitialType && inputIsEmpty ) {\n /** Show plus button */\r\n editor.toolbar.showPlusButton();\n }\n };\r\n\r\n /**\r\n * This method allows to define, is caret in contenteditable element or not.\r\n *\r\n * @private\r\n *\r\n * @description Otherwise, if we get TEXT node from range container, that will means we have input index.\r\n * In this case we use default browsers behaviour (if plugin allows that) or overwritten action.\r\n * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always\r\n * specifies to the first-level block. Other cases we just ignore.\r\n */\r\n var detectWhenClickedOnFirstLevelBlockArea_ = function () {\n var selection = window.getSelection(),\r\n anchorNode = selection.anchorNode,\r\n flag = false;\r\n\r\n if (selection.rangeCount === 0) {\n editor.content.editorAreaHightlighted = true;\n } else {\n if (!editor.core.isDomNode(anchorNode)) {\n anchorNode = anchorNode.parentNode;\n }\r\n\r\n /** Already founded, without loop */\r\n if (anchorNode.contentEditable == 'true') {\n flag = true;\n }\r\n\r\n while (anchorNode.contentEditable != 'true') {\n anchorNode = anchorNode.parentNode;\r\n\r\n if (anchorNode.contentEditable == 'true') {\n flag = true;\n }\r\n\r\n if (anchorNode == document.body) {\n break;\n }\n }\r\n\r\n /** If editable element founded, flag is \"TRUE\", Therefore we return \"FALSE\" */\r\n editor.content.editorAreaHightlighted = !flag;\n }\n };\r\n\r\n /**\r\n * Toolbar button click handler\r\n *\r\n * @param {Object} event - cursor to the button\r\n * @protected\r\n *\r\n * @description gets current tool and calls render method\r\n */\r\n callbacks.toolbarButtonClicked = function (event) {\n var button = this;\r\n\r\n editor.toolbar.current = button.dataset.type;\r\n\r\n editor.toolbar.toolbox.toolClicked(event);\r\n editor.toolbar.close();\n };\r\n\r\n /**\r\n * Show or Hide toolbox when plus button is clicked\r\n */\r\n callbacks.plusButtonClicked = function () {\n if (!editor.nodes.toolbox.classList.contains('opened')) {\n editor.toolbar.toolbox.open();\n } else {\n editor.toolbar.toolbox.close();\n }\n };\r\n\r\n /**\r\n * Block handlers for KeyDown events\r\n *\r\n * @protected\r\n * @param {Object} event\r\n *\r\n * Handles keydowns on block\r\n * @see blockRightOrDownArrowPressed_\r\n * @see backspacePressed_\r\n * @see blockLeftOrUpArrowPressed_\r\n */\r\n callbacks.blockKeydown = function (event) {\n let block = event.target; // event.target is input\r\n\r\n switch (event.keyCode) {\n case editor.core.keys.DOWN:\r\n case editor.core.keys.RIGHT:\r\n blockRightOrDownArrowPressed_(event);\r\n break;\r\n\r\n case editor.core.keys.BACKSPACE:\r\n backspacePressed_(block, event);\r\n break;\r\n\r\n case editor.core.keys.UP:\r\n case editor.core.keys.LEFT:\r\n blockLeftOrUpArrowPressed_(event);\r\n break;\n }\n };\r\n\r\n /**\r\n * RIGHT or DOWN keydowns on block\r\n *\r\n * @param {Object} event\r\n * @private\r\n *\r\n * @description watches the selection and gets closest editable element.\r\n * Uses method getDeepestTextNodeFromPosition to get the last node of next block\r\n * Sets caret if it is contenteditable\r\n */\r\n var blockRightOrDownArrowPressed_ = function (event) {\n var selection = window.getSelection(),\r\n inputs = editor.state.inputs,\r\n focusedNode = selection.anchorNode,\r\n focusedNodeHolder;\r\n\r\n /** Check for caret existance */\r\n if (!focusedNode) {\n return false;\n }\r\n\r\n /** Looking for closest (parent) contentEditable element of focused node */\r\n while (focusedNode.contentEditable != 'true') {\n focusedNodeHolder = focusedNode.parentNode;\r\n focusedNode = focusedNodeHolder;\n }\r\n\r\n /** Input index in DOM level */\r\n var editableElementIndex = 0;\r\n\r\n while (focusedNode != inputs[editableElementIndex]) {\n editableElementIndex ++;\n }\r\n\r\n /**\r\n * Founded contentEditable element doesn't have childs\r\n * Or maybe New created block\r\n */\r\n if (!focusedNode.textContent) {\n editor.caret.setToNextBlock(editableElementIndex);\r\n return;\n }\r\n\r\n /**\r\n * Do nothing when caret doesn not reaches the end of last child\r\n */\r\n var caretInLastChild = false,\r\n caretAtTheEndOfText = false;\r\n\r\n var lastChild,\r\n deepestTextnode;\r\n\r\n lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1 ];\r\n\r\n if (editor.core.isDomNode(lastChild)) {\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length);\n } else {\n deepestTextnode = lastChild;\n }\r\n\r\n caretInLastChild = selection.anchorNode == deepestTextnode;\r\n caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset;\r\n\r\n if ( !caretInLastChild || !caretAtTheEndOfText ) {\n editor.core.log('arrow [down|right] : caret does not reached the end');\r\n return false;\n }\r\n\r\n editor.caret.setToNextBlock(editableElementIndex);\n };\r\n\r\n /**\r\n * LEFT or UP keydowns on block\r\n *\r\n * @param {Object} event\r\n * @private\r\n *\r\n * watches the selection and gets closest editable element.\r\n * Uses method getDeepestTextNodeFromPosition to get the last node of previous block\r\n * Sets caret if it is contenteditable\r\n *\r\n */\r\n var blockLeftOrUpArrowPressed_ = function (event) {\n var selection = window.getSelection(),\r\n inputs = editor.state.inputs,\r\n focusedNode = selection.anchorNode,\r\n focusedNodeHolder;\r\n\r\n /** Check for caret existance */\r\n if (!focusedNode) {\n return false;\n }\r\n\r\n /**\r\n * LEFT or UP not at the beginning\r\n */\r\n if ( selection.anchorOffset !== 0) {\n return false;\n }\r\n\r\n /** Looking for parent contentEditable block */\r\n while (focusedNode.contentEditable != 'true') {\n focusedNodeHolder = focusedNode.parentNode;\r\n focusedNode = focusedNodeHolder;\n }\r\n\r\n /** Input index in DOM level */\r\n var editableElementIndex = 0;\r\n\r\n while (focusedNode != inputs[editableElementIndex]) {\n editableElementIndex ++;\n }\r\n\r\n /**\r\n * Do nothing if caret is not at the beginning of first child\r\n */\r\n var caretInFirstChild = false,\r\n caretAtTheBeginning = false;\r\n\r\n var firstChild,\r\n deepestTextnode;\r\n\r\n /**\r\n * Founded contentEditable element doesn't have childs\r\n * Or maybe New created block\r\n */\r\n if (!focusedNode.textContent) {\n editor.caret.setToPreviousBlock(editableElementIndex);\r\n return;\n }\r\n\r\n firstChild = focusedNode.childNodes[0];\r\n\r\n if (editor.core.isDomNode(firstChild)) {\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0);\n } else {\n deepestTextnode = firstChild;\n }\r\n\r\n caretInFirstChild = selection.anchorNode == deepestTextnode;\r\n caretAtTheBeginning = selection.anchorOffset === 0;\r\n\r\n if ( caretInFirstChild && caretAtTheBeginning ) {\n editor.caret.setToPreviousBlock(editableElementIndex);\n }\n };\r\n\r\n /**\r\n * Handles backspace keydown\r\n *\r\n * @param {Element} block\r\n * @param {Object} event\r\n * @private\r\n *\r\n * @description if block is empty, delete the block and set caret to the previous block\r\n * If block is not empty, try to merge two blocks - current and previous\r\n * But it we try'n to remove first block, then we should set caret to the next block, not previous.\r\n * If we removed the last block, create new one\r\n */\r\n var backspacePressed_ = function (block, event) {\n var currentInputIndex = editor.caret.getCurrentInputIndex(),\r\n range,\r\n selectionLength,\r\n firstLevelBlocksCount;\r\n\r\n if (editor.core.isNativeInput(event.target)) {\n /** If input value is empty - remove block */\r\n if (event.target.value.trim() == '') {\n block.remove();\n } else {\n return;\n }\n }\r\n\r\n if (block.textContent.trim()) {\n range = editor.content.getRange();\r\n selectionLength = range.endOffset - range.startOffset;\r\n\r\n if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {\n editor.content.mergeBlocks(currentInputIndex);\n } else {\n return;\n }\n }\r\n\r\n if (!selectionLength) {\n block.remove();\n }\r\n\r\n\r\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\r\n\r\n /**\r\n * If all blocks are removed\r\n */\r\n if (firstLevelBlocksCount === 0) {\n /** update currentNode variable */\r\n editor.content.currentNode = null;\r\n\r\n /** Inserting new empty initial block */\r\n editor.ui.addInitialBlock();\r\n\r\n /** Updating inputs state after deleting last block */\r\n editor.ui.saveInputs();\r\n\r\n /** Set to current appended block */\r\n window.setTimeout(function () {\n editor.caret.setToPreviousBlock(1);\n }, 10);\n } else {\n if (editor.caret.inputIndex !== 0) {\n /** Target block is not first */\r\n editor.caret.setToPreviousBlock(editor.caret.inputIndex);\n } else {\n /** If we try to delete first block */\r\n editor.caret.setToNextBlock(editor.caret.inputIndex);\n }\n }\r\n\r\n editor.toolbar.move();\r\n\r\n if (!editor.toolbar.opened) {\n editor.toolbar.open();\n }\r\n\r\n /** Updating inputs state */\r\n editor.ui.saveInputs();\r\n\r\n /** Prevent default browser behaviour */\r\n event.preventDefault();\n };\r\n\r\n /**\r\n * used by UI module\r\n * Clicks on block settings button\r\n *\r\n * @param {Object} event\r\n * @protected\r\n * @description Opens toolbar settings\r\n */\r\n callbacks.showSettingsButtonClicked = function (event) {\n /**\r\n * Get type of current block\r\n * It uses to append settings from tool.settings property.\r\n * ...\r\n * Type is stored in data-type attribute on block\r\n */\r\n var currentToolType = editor.content.currentNode.dataset.tool;\r\n\r\n editor.toolbar.settings.toggle(currentToolType);\r\n\r\n /** Close toolbox when settings button is active */\r\n editor.toolbar.toolbox.close();\r\n editor.toolbar.settings.hideRemoveActions();\n };\r\n\r\n return callbacks;\n})({});","/**\r\n * Codex Editor Caret Module\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = (function (caret) {\n let editor = codex.editor;\r\n\r\n /**\r\n * @var {int} InputIndex - editable element in DOM\r\n */\r\n caret.inputIndex = null;\r\n\r\n /**\r\n * @var {int} offset - caret position in a text node.\r\n */\r\n caret.offset = null;\r\n\r\n /**\r\n * @var {int} focusedNodeIndex - we get index of child node from first-level block\r\n */\r\n caret.focusedNodeIndex = null;\r\n\r\n /**\r\n * Creates Document Range and sets caret to the element.\r\n * @protected\r\n * @uses caret.save — if you need to save caret position\r\n * @param {Element} el - Changed Node.\r\n */\r\n caret.set = function ( el, index, offset) {\n offset = offset || caret.offset || 0;\r\n index = index || caret.focusedNodeIndex || 0;\r\n\r\n var childs = el.childNodes,\r\n nodeToSet;\r\n\r\n if ( childs.length === 0 ) {\n nodeToSet = el;\n } else {\n nodeToSet = childs[index];\n }\r\n\r\n /** If Element is INPUT */\r\n if (el.contentEditable != 'true') {\n el.focus();\r\n return;\n }\r\n\r\n if (editor.core.isDomNode(nodeToSet)) {\n nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);\n }\r\n\r\n var range = document.createRange(),\r\n selection = window.getSelection();\r\n\r\n window.setTimeout(function () {\n range.setStart(nodeToSet, offset);\r\n range.setEnd(nodeToSet, offset);\r\n\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n\r\n editor.caret.saveCurrentInputIndex();\n }, 20);\n };\r\n\r\n /**\r\n * @protected\r\n * Updates index of input and saves it in caret object\r\n */\r\n caret.saveCurrentInputIndex = function () {\n /** Index of Input that we paste sanitized content */\r\n var selection = window.getSelection(),\r\n inputs = editor.state.inputs,\r\n focusedNode = selection.anchorNode,\r\n focusedNodeHolder;\r\n\r\n if (!focusedNode) {\n return;\n }\r\n\r\n /** Looking for parent contentEditable block */\r\n while (focusedNode.contentEditable != 'true') {\n focusedNodeHolder = focusedNode.parentNode;\r\n focusedNode = focusedNodeHolder;\n }\r\n\r\n /** Input index in DOM level */\r\n var editableElementIndex = 0;\r\n\r\n while (focusedNode != inputs[editableElementIndex]) {\n editableElementIndex ++;\n }\r\n\r\n caret.inputIndex = editableElementIndex;\n };\r\n\r\n /**\r\n * Returns current input index (caret object)\r\n */\r\n caret.getCurrentInputIndex = function () {\n return caret.inputIndex;\n };\r\n\r\n /**\r\n * @param {int} index - index of first-level block after that we set caret into next input\r\n */\r\n caret.setToNextBlock = function (index) {\n var inputs = editor.state.inputs,\r\n nextInput = inputs[index + 1];\r\n\r\n if (!nextInput) {\n editor.core.log('We are reached the end');\r\n return;\n }\r\n\r\n /**\r\n * When new Block created or deleted content of input\r\n * We should add some text node to set caret\r\n */\r\n if (!nextInput.childNodes.length) {\n var emptyTextElement = document.createTextNode('');\r\n\r\n nextInput.appendChild(emptyTextElement);\n }\r\n\r\n editor.caret.inputIndex = index + 1;\r\n editor.caret.set(nextInput, 0, 0);\r\n editor.content.workingNodeChanged(nextInput);\n };\r\n\r\n /**\r\n * @param {int} index - index of target input.\r\n * Sets caret to input with this index\r\n */\r\n caret.setToBlock = function (index) {\n var inputs = editor.state.inputs,\r\n targetInput = inputs[index];\r\n\r\n if ( !targetInput ) {\n return;\n }\r\n\r\n /**\r\n * When new Block created or deleted content of input\r\n * We should add some text node to set caret\r\n */\r\n if (!targetInput.childNodes.length) {\n var emptyTextElement = document.createTextNode('');\r\n\r\n targetInput.appendChild(emptyTextElement);\n }\r\n\r\n editor.caret.inputIndex = index;\r\n editor.caret.set(targetInput, 0, 0);\r\n editor.content.workingNodeChanged(targetInput);\n };\r\n\r\n /**\r\n * @param {int} index - index of input\r\n */\r\n caret.setToPreviousBlock = function (index) {\n index = index || 0;\r\n\r\n var inputs = editor.state.inputs,\r\n previousInput = inputs[index - 1],\r\n lastChildNode,\r\n lengthOfLastChildNode,\r\n emptyTextElement;\r\n\r\n\r\n if (!previousInput) {\n editor.core.log('We are reached first node');\r\n return;\n }\r\n\r\n lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length);\r\n lengthOfLastChildNode = lastChildNode.length;\r\n\r\n /**\r\n * When new Block created or deleted content of input\r\n * We should add some text node to set caret\r\n */\r\n if (!previousInput.childNodes.length) {\n emptyTextElement = document.createTextNode('');\r\n previousInput.appendChild(emptyTextElement);\n }\r\n editor.caret.inputIndex = index - 1;\r\n editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode);\r\n editor.content.workingNodeChanged(inputs[index - 1]);\n };\r\n\r\n caret.position = {\r\n\r\n atStart : function () {\n var selection = window.getSelection(),\r\n anchorOffset = selection.anchorOffset,\r\n anchorNode = selection.anchorNode,\r\n firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode),\r\n pluginsRender = firstLevelBlock.childNodes[0];\r\n\r\n if (!editor.core.isDomNode(anchorNode)) {\n anchorNode = anchorNode.parentNode;\n }\r\n\r\n var isFirstNode = anchorNode === pluginsRender.childNodes[0],\r\n isOffsetZero = anchorOffset === 0;\r\n\r\n return isFirstNode && isOffsetZero;\n },\r\n\r\n atTheEnd : function () {\n var selection = window.getSelection(),\r\n anchorOffset = selection.anchorOffset,\r\n anchorNode = selection.anchorNode;\r\n\r\n /** Caret is at the end of input */\r\n return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length;\n }\r\n };\r\n\r\n\r\n /**\r\n * Inserts node at the caret location\r\n * @param {HTMLElement|DocumentFragment} node\r\n */\r\n caret.insertNode = function (node) {\n var selection, range,\r\n lastNode = node;\r\n\r\n if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) {\n lastNode = node.lastChild;\n }\r\n\r\n selection = window.getSelection();\r\n\r\n range = selection.getRangeAt(0);\r\n range.deleteContents();\r\n\r\n range.insertNode(node);\r\n\r\n range.setStartAfter(lastNode);\r\n range.collapse(true);\r\n\r\n selection.removeAllRanges();\r\n selection.addRange(range);\n };\r\n\r\n return caret;\n})({});","/**\r\n * Codex Editor Content Module\r\n * Works with DOM\r\n *\r\n * @class Content\r\n * @classdesc Class works provides COdex Editor appearance logic\r\n *\r\n * @author Codex Team\r\n * @version 2.0.0\r\n */\r\n\r\nimport $ from '../dom';\r\n\r\nmodule.exports = class Content {\n /**\r\n * Module key name\r\n * @returns {string}\r\n */\r\n static get name() {\n return 'Content';\n }\r\n\r\n /**\r\n * @constructor\r\n *\r\n * @param {EditorConfig} config\r\n */\r\n constructor(config) {\n this.config = config;\r\n this.Editor = null;\r\n\r\n this.CSS = {\r\n block: 'ce-block',\r\n content: 'ce-block__content',\r\n stretched: 'ce-block--stretched',\r\n highlighted: 'ce-block--highlighted',\r\n };\r\n\r\n this._currentNode = null;\r\n this._currentIndex = 0;\n }\r\n\r\n /**\r\n * Editor modules setter\r\n * @param {object} Editor\r\n */\r\n set state(Editor) {\n this.Editor = Editor;\n }\r\n\r\n /**\r\n * Get current working node\r\n *\r\n * @returns {null|HTMLElement}\r\n */\r\n get currentNode() {\n return this._currentNode;\n }\r\n\r\n /**\r\n * Set working node. Working node should be first level block, so we find it before set one to _currentNode property\r\n *\r\n * @param {HTMLElement} node\r\n */\r\n set currentNode(node) {\n let firstLevelBlock = this.getFirstLevelBlock(node);\r\n\r\n this._currentNode = firstLevelBlock;\n }\r\n\r\n\r\n /**\r\n * @private\r\n * @param pluginHTML\r\n * @param {Boolean} isStretched - make stretched block or not\r\n *\r\n * @description adds necessary information to wrap new created block by first-level holder\r\n */\r\n composeBlock_(pluginHTML, isStretched = false) {\n let block = $.make('DIV', this.CSS.block),\r\n blockContent = $.make('DIV', this.CSS.content);\r\n\r\n blockContent.appendChild(pluginHTML);\r\n block.appendChild(blockContent);\r\n\r\n if (isStretched) {\n blockContent.classList.add(this.CSS.stretched);\n }\r\n\r\n block.dataset.toolId = this._currentIndex++;\r\n\r\n return block;\n };\r\n\r\n /**\r\n * Finds first-level block\r\n * @description looks for first-level block.\r\n * gets parent while node is not first-level\r\n *\r\n * @param {Element} node - selected or clicked in redactors area node\r\n * @protected\r\n *\r\n */\r\n getFirstLevelBlock(node) {\n if (!$.isElement(node)) {\n node = node.parentNode;\n }\r\n\r\n if (node === this.Editor.ui.nodes.redactor || node === document.body) {\n return null;\n } else {\n while(node.classList && !node.classList.contains(this.CSS.block)) {\n node = node.parentNode;\n }\r\n\r\n return node;\n }\n };\r\n\r\n /**\r\n * Insert new block to working area\r\n *\r\n * @param {HTMLElement} tool\r\n *\r\n * @returns {Number} tool index\r\n *\r\n */\r\n insertBlock(tool) {\n let newBlock = this.composeBlock_(tool);\r\n\r\n if (this.currentNode) {\n this.currentNode.insertAdjacentElement('afterend', newBlock);\n } else {\n /**\r\n * If redactor is empty, append as first child\r\n */\r\n this.Editor.ui.nodes.redactor.appendChild(newBlock);\n }\r\n\r\n /**\r\n * Set new node as current\r\n */\r\n this.currentNode = newBlock;\r\n\r\n return newBlock.dataset.toolId;\n }\n};\r\n\r\n// module.exports = (function (content) {\r\n//\r\n// let editor = codex.editor;\r\n//\r\n// /**\r\n// * Links to current active block\r\n// * @type {null | Element}\r\n// */\r\n// content.currentNode = null;\r\n//\r\n// /**\r\n// * clicked in redactor area\r\n// * @type {null | Boolean}\r\n// */\r\n// content.editorAreaHightlighted = null;\r\n//\r\n// /**\r\n// * @deprecated\r\n// * Synchronizes redactor with original textarea\r\n// */\r\n// content.sync = function () {\r\n//\r\n// editor.core.log('syncing...');\r\n//\r\n// /**\r\n// * Save redactor content to editor.state\r\n// */\r\n// editor.state.html = editor.nodes.redactor.innerHTML;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Appends background to the block\r\n// *\r\n// * @description add CSS class to highlight visually first-level block area\r\n// */\r\n// content.markBlock = function () {\r\n//\r\n// editor.content.currentNode.classList.add(editor.ui.className.BLOCK_HIGHLIGHTED);\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Clear background\r\n// *\r\n// * @description clears styles that highlights block\r\n// */\r\n// content.clearMark = function () {\r\n//\r\n// if (editor.content.currentNode) {\r\n//\r\n// editor.content.currentNode.classList.remove(editor.ui.className.BLOCK_HIGHLIGHTED);\r\n//\r\n// }\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Finds first-level block\r\n// *\r\n// * @param {Element} node - selected or clicked in redactors area node\r\n// * @protected\r\n// *\r\n// * @description looks for first-level block.\r\n// * gets parent while node is not first-level\r\n// */\r\n// content.getFirstLevelBlock = function (node) {\r\n//\r\n// if (!editor.core.isDomNode(node)) {\r\n//\r\n// node = node.parentNode;\r\n//\r\n// }\r\n//\r\n// if (node === editor.nodes.redactor || node === document.body) {\r\n//\r\n// return null;\r\n//\r\n// } else {\r\n//\r\n// while(!node.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\r\n//\r\n// node = node.parentNode;\r\n//\r\n// }\r\n//\r\n// return node;\r\n//\r\n// }\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Trigger this event when working node changed\r\n// * @param {Element} targetNode - first-level of this node will be current\r\n// * @protected\r\n// *\r\n// * @description If targetNode is first-level then we set it as current else we look for parents to find first-level\r\n// */\r\n// content.workingNodeChanged = function (targetNode) {\r\n//\r\n// /** Clear background from previous marked block before we change */\r\n// editor.content.clearMark();\r\n//\r\n// if (!targetNode) {\r\n//\r\n// return;\r\n//\r\n// }\r\n//\r\n// content.currentNode = content.getFirstLevelBlock(targetNode);\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Replaces one redactor block with another\r\n// * @protected\r\n// * @param {Element} targetBlock - block to replace. Mostly currentNode.\r\n// * @param {Element} newBlock\r\n// * @param {string} newBlockType - type of new block; we need to store it to data-attribute\r\n// *\r\n// * [!] Function does not saves old block content.\r\n// * You can get it manually and pass with newBlock.innerHTML\r\n// */\r\n// content.replaceBlock = function (targetBlock, newBlock) {\r\n//\r\n// if (!targetBlock || !newBlock) {\r\n//\r\n// editor.core.log('replaceBlock: missed params');\r\n// return;\r\n//\r\n// }\r\n//\r\n// /** If target-block is not a frist-level block, then we iterate parents to find it */\r\n// while(!targetBlock.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\r\n//\r\n// targetBlock = targetBlock.parentNode;\r\n//\r\n// }\r\n//\r\n// /** Replacing */\r\n// editor.nodes.redactor.replaceChild(newBlock, targetBlock);\r\n//\r\n// /**\r\n// * Set new node as current\r\n// */\r\n// editor.content.workingNodeChanged(newBlock);\r\n//\r\n// /**\r\n// * Add block handlers\r\n// */\r\n// editor.ui.addBlockHandlers(newBlock);\r\n//\r\n// /**\r\n// * Save changes\r\n// */\r\n// editor.ui.saveInputs();\r\n//\r\n// };\r\n//\r\n// /**\r\n// * @protected\r\n// *\r\n// * Inserts new block to redactor\r\n// * Wrapps block into a DIV with BLOCK_CLASSNAME class\r\n// *\r\n// * @param blockData {object}\r\n// * @param blockData.block {Element} element with block content\r\n// * @param blockData.type {string} block plugin\r\n// * @param needPlaceCaret {bool} pass true to set caret in new block\r\n// *\r\n// */\r\n// content.insertBlock = function ( blockData, needPlaceCaret ) {\r\n//\r\n// var workingBlock = editor.content.currentNode,\r\n// newBlockContent = blockData.block,\r\n// blockType = blockData.type,\r\n// isStretched = blockData.stretched;\r\n//\r\n// var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched);\r\n//\r\n// if (workingBlock) {\r\n//\r\n// editor.core.insertAfter(workingBlock, newBlock);\r\n//\r\n// } else {\r\n//\r\n// /**\r\n// * If redactor is empty, append as first child\r\n// */\r\n// editor.nodes.redactor.appendChild(newBlock);\r\n//\r\n// }\r\n//\r\n// /**\r\n// * Block handler\r\n// */\r\n// editor.ui.addBlockHandlers(newBlock);\r\n//\r\n// /**\r\n// * Set new node as current\r\n// */\r\n// editor.content.workingNodeChanged(newBlock);\r\n//\r\n// /**\r\n// * Save changes\r\n// */\r\n// editor.ui.saveInputs();\r\n//\r\n//\r\n// if ( needPlaceCaret ) {\r\n//\r\n// /**\r\n// * If we don't know input index then we set default value -1\r\n// */\r\n// var currentInputIndex = editor.caret.getCurrentInputIndex() || -1;\r\n//\r\n//\r\n// if (currentInputIndex == -1) {\r\n//\r\n//\r\n// var editableElement = newBlock.querySelector('[contenteditable]'),\r\n// emptyText = document.createTextNode('');\r\n//\r\n// editableElement.appendChild(emptyText);\r\n// editor.caret.set(editableElement, 0, 0);\r\n//\r\n// editor.toolbar.move();\r\n// editor.toolbar.showPlusButton();\r\n//\r\n//\r\n// } else {\r\n//\r\n// if (currentInputIndex === editor.state.inputs.length - 1)\r\n// return;\r\n//\r\n// /** Timeout for browsers execution */\r\n// window.setTimeout(function () {\r\n//\r\n// /** Setting to the new input */\r\n// editor.caret.setToNextBlock(currentInputIndex);\r\n// editor.toolbar.move();\r\n// editor.toolbar.open();\r\n//\r\n// }, 10);\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// /**\r\n// * Block is inserted, wait for new click that defined focusing on editors area\r\n// * @type {boolean}\r\n// */\r\n// content.editorAreaHightlighted = false;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Replaces blocks with saving content\r\n// * @protected\r\n// * @param {Element} noteToReplace\r\n// * @param {Element} newNode\r\n// * @param {Element} blockType\r\n// */\r\n// content.switchBlock = function (blockToReplace, newBlock, tool) {\r\n//\r\n// tool = tool || editor.content.currentNode.dataset.tool;\r\n// var newBlockComposed = composeNewBlock_(newBlock, tool);\r\n//\r\n// /** Replacing */\r\n// editor.content.replaceBlock(blockToReplace, newBlockComposed);\r\n//\r\n// /** Save new Inputs when block is changed */\r\n// editor.ui.saveInputs();\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Iterates between child noted and looking for #text node on deepest level\r\n// * @protected\r\n// *\r\n// * @param {Element} block - node where find\r\n// * @param {int} postiton - starting postion\r\n// * Example: childNodex.length to find from the end\r\n// * or 0 to find from the start\r\n// * @return {Text} block\r\n// * @uses DFS\r\n// */\r\n// content.getDeepestTextNodeFromPosition = function (block, position) {\r\n//\r\n// /**\r\n// * Clear Block from empty and useless spaces with trim.\r\n// * Such nodes we should remove\r\n// */\r\n// var blockChilds = block.childNodes,\r\n// index,\r\n// node,\r\n// text;\r\n//\r\n// for(index = 0; index < blockChilds.length; index++) {\r\n//\r\n// node = blockChilds[index];\r\n//\r\n// if (node.nodeType == editor.core.nodeTypes.TEXT) {\r\n//\r\n// text = node.textContent.trim();\r\n//\r\n// /** Text is empty. We should remove this child from node before we start DFS\r\n// * decrease the quantity of childs.\r\n// */\r\n// if (text === '') {\r\n//\r\n// block.removeChild(node);\r\n// position--;\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// if (block.childNodes.length === 0) {\r\n//\r\n// return document.createTextNode('');\r\n//\r\n// }\r\n//\r\n// /** Setting default position when we deleted all empty nodes */\r\n// if ( position < 0 )\r\n// position = 1;\r\n//\r\n// var lookingFromStart = false;\r\n//\r\n// /** For looking from START */\r\n// if (position === 0) {\r\n//\r\n// lookingFromStart = true;\r\n// position = 1;\r\n//\r\n// }\r\n//\r\n// while ( position ) {\r\n//\r\n// /** initial verticle of node. */\r\n// if ( lookingFromStart ) {\r\n//\r\n// block = block.childNodes[0];\r\n//\r\n// } else {\r\n//\r\n// block = block.childNodes[position - 1];\r\n//\r\n// }\r\n//\r\n// if ( block.nodeType == editor.core.nodeTypes.TAG ) {\r\n//\r\n// position = block.childNodes.length;\r\n//\r\n// } else if (block.nodeType == editor.core.nodeTypes.TEXT ) {\r\n//\r\n// position = 0;\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// return block;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * @private\r\n// * @param {Element} block - current plugins render\r\n// * @param {String} tool - plugins name\r\n// * @param {Boolean} isStretched - make stretched block or not\r\n// *\r\n// * @description adds necessary information to wrap new created block by first-level holder\r\n// */\r\n// var composeNewBlock_ = function (block, tool, isStretched) {\r\n//\r\n// var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),\r\n// blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});\r\n//\r\n// blockContent.appendChild(block);\r\n// newBlock.appendChild(blockContent);\r\n//\r\n// if (isStretched) {\r\n//\r\n// blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED);\r\n//\r\n// }\r\n//\r\n// newBlock.dataset.tool = tool;\r\n// return newBlock;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Returns Range object of current selection\r\n// * @protected\r\n// */\r\n// content.getRange = function () {\r\n//\r\n// var selection = window.getSelection().getRangeAt(0);\r\n//\r\n// return selection;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Divides block in two blocks (after and before caret)\r\n// *\r\n// * @protected\r\n// * @param {int} inputIndex - target input index\r\n// *\r\n// * @description splits current input content to the separate blocks\r\n// * When enter is pressed among the words, that text will be splited.\r\n// */\r\n// content.splitBlock = function (inputIndex) {\r\n//\r\n// var selection = window.getSelection(),\r\n// anchorNode = selection.anchorNode,\r\n// anchorNodeText = anchorNode.textContent,\r\n// caretOffset = selection.anchorOffset,\r\n// textBeforeCaret,\r\n// textNodeBeforeCaret,\r\n// textAfterCaret,\r\n// textNodeAfterCaret;\r\n//\r\n// var currentBlock = editor.content.currentNode.querySelector('[contentEditable]');\r\n//\r\n//\r\n// textBeforeCaret = anchorNodeText.substring(0, caretOffset);\r\n// textAfterCaret = anchorNodeText.substring(caretOffset);\r\n//\r\n// textNodeBeforeCaret = document.createTextNode(textBeforeCaret);\r\n//\r\n// if (textAfterCaret) {\r\n//\r\n// textNodeAfterCaret = document.createTextNode(textAfterCaret);\r\n//\r\n// }\r\n//\r\n// var previousChilds = [],\r\n// nextChilds = [],\r\n// reachedCurrent = false;\r\n//\r\n// if (textNodeAfterCaret) {\r\n//\r\n// nextChilds.push(textNodeAfterCaret);\r\n//\r\n// }\r\n//\r\n// for ( var i = 0, child; !!(child = currentBlock.childNodes[i]); i++) {\r\n//\r\n// if ( child != anchorNode ) {\r\n//\r\n// if ( !reachedCurrent ) {\r\n//\r\n// previousChilds.push(child);\r\n//\r\n// } else {\r\n//\r\n// nextChilds.push(child);\r\n//\r\n// }\r\n//\r\n// } else {\r\n//\r\n// reachedCurrent = true;\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// /** Clear current input */\r\n// editor.state.inputs[inputIndex].innerHTML = '';\r\n//\r\n// /**\r\n// * Append all childs founded before anchorNode\r\n// */\r\n// var previousChildsLength = previousChilds.length;\r\n//\r\n// for(i = 0; i < previousChildsLength; i++) {\r\n//\r\n// editor.state.inputs[inputIndex].appendChild(previousChilds[i]);\r\n//\r\n// }\r\n//\r\n// editor.state.inputs[inputIndex].appendChild(textNodeBeforeCaret);\r\n//\r\n// /**\r\n// * Append text node which is after caret\r\n// */\r\n// var nextChildsLength = nextChilds.length,\r\n// newNode = document.createElement('div');\r\n//\r\n// for(i = 0; i < nextChildsLength; i++) {\r\n//\r\n// newNode.appendChild(nextChilds[i]);\r\n//\r\n// }\r\n//\r\n// newNode = newNode.innerHTML;\r\n//\r\n// /** This type of block creates when enter is pressed */\r\n// var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\r\n//\r\n// /**\r\n// * Make new paragraph with text after caret\r\n// */\r\n// editor.content.insertBlock({\r\n// type : NEW_BLOCK_TYPE,\r\n// block : editor.tools[NEW_BLOCK_TYPE].render({\r\n// text : newNode\r\n// })\r\n// }, true );\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Merges two blocks — current and target\r\n// * If target index is not exist, then previous will be as target\r\n// *\r\n// * @protected\r\n// * @param {int} currentInputIndex\r\n// * @param {int} targetInputIndex\r\n// *\r\n// * @description gets two inputs indexes and merges into one\r\n// */\r\n// content.mergeBlocks = function (currentInputIndex, targetInputIndex) {\r\n//\r\n// /** If current input index is zero, then prevent method execution */\r\n// if (currentInputIndex === 0) {\r\n//\r\n// return;\r\n//\r\n// }\r\n//\r\n// var targetInput,\r\n// currentInputContent = editor.state.inputs[currentInputIndex].innerHTML;\r\n//\r\n// if (!targetInputIndex) {\r\n//\r\n// targetInput = editor.state.inputs[currentInputIndex - 1];\r\n//\r\n// } else {\r\n//\r\n// targetInput = editor.state.inputs[targetInputIndex];\r\n//\r\n// }\r\n//\r\n// targetInput.innerHTML += currentInputContent;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Iterates all right siblings and parents, which has right siblings\r\n// * while it does not reached the first-level block\r\n// *\r\n// * @param {Element} node\r\n// * @return {boolean}\r\n// */\r\n// content.isLastNode = function (node) {\r\n//\r\n// // console.log('погнали перебор родителей');\r\n//\r\n// var allChecked = false;\r\n//\r\n// while ( !allChecked ) {\r\n//\r\n// // console.log('Смотрим на %o', node);\r\n// // console.log('Проверим, пустые ли соседи справа');\r\n//\r\n// if ( !allSiblingsEmpty_(node) ) {\r\n//\r\n// // console.log('Есть непустые соседи. Узел не последний. Выходим.');\r\n// return false;\r\n//\r\n// }\r\n//\r\n// node = node.parentNode;\r\n//\r\n// /**\r\n// * Проверяем родителей до тех пор, пока не найдем блок первого уровня\r\n// */\r\n// if ( node.classList.contains(editor.ui.className.BLOCK_CONTENT) ) {\r\n//\r\n// allChecked = true;\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// return true;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Checks if all element right siblings is empty\r\n// * @param node\r\n// */\r\n// var allSiblingsEmpty_ = function (node) {\r\n//\r\n// /**\r\n// * Нужно убедиться, что после пустого соседа ничего нет\r\n// */\r\n// var sibling = node.nextSibling;\r\n//\r\n// while ( sibling ) {\r\n//\r\n// if (sibling.textContent.length) {\r\n//\r\n// return false;\r\n//\r\n// }\r\n//\r\n// sibling = sibling.nextSibling;\r\n//\r\n// }\r\n//\r\n// return true;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * @public\r\n// *\r\n// * @param {string} htmlData - html content as string\r\n// * @param {string} plainData - plain text\r\n// * @return {string} - html content as string\r\n// */\r\n// content.wrapTextWithParagraphs = function (htmlData, plainData) {\r\n//\r\n// if (!htmlData.trim()) {\r\n//\r\n// return wrapPlainTextWithParagraphs(plainData);\r\n//\r\n// }\r\n//\r\n// var wrapper = document.createElement('DIV'),\r\n// newWrapper = document.createElement('DIV'),\r\n// i,\r\n// paragraph,\r\n// firstLevelBlocks = ['DIV', 'P'],\r\n// blockTyped,\r\n// node;\r\n//\r\n// /**\r\n// * Make HTML Element to Wrap Text\r\n// * It allows us to work with input data as HTML content\r\n// */\r\n// wrapper.innerHTML = htmlData;\r\n// paragraph = document.createElement('P');\r\n//\r\n// for (i = 0; i < wrapper.childNodes.length; i++) {\r\n//\r\n// node = wrapper.childNodes[i];\r\n//\r\n// blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1;\r\n//\r\n// /**\r\n// * If node is first-levet\r\n// * we add this node to our new wrapper\r\n// */\r\n// if ( blockTyped ) {\r\n//\r\n// /**\r\n// * If we had splitted inline nodes to paragraph before\r\n// */\r\n// if ( paragraph.childNodes.length ) {\r\n//\r\n// newWrapper.appendChild(paragraph.cloneNode(true));\r\n//\r\n// /** empty paragraph */\r\n// paragraph = null;\r\n// paragraph = document.createElement('P');\r\n//\r\n// }\r\n//\r\n// newWrapper.appendChild(node.cloneNode(true));\r\n//\r\n// } else {\r\n//\r\n// /** Collect all inline nodes to one as paragraph */\r\n// paragraph.appendChild(node.cloneNode(true));\r\n//\r\n// /** if node is last we should append this node to paragraph and paragraph to new wrapper */\r\n// if ( i == wrapper.childNodes.length - 1 ) {\r\n//\r\n// newWrapper.appendChild(paragraph.cloneNode(true));\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// return newWrapper.innerHTML;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Splits strings on new line and wraps paragraphs with

    tag\r\n// * @param plainText\r\n// * @returns {string}\r\n// */\r\n// var wrapPlainTextWithParagraphs = function (plainText) {\r\n//\r\n// if (!plainText) return '';\r\n//\r\n// return '

    ' + plainText.split('\\n\\n').join('

    ') + '

    ';\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Finds closest Contenteditable parent from Element\r\n// * @param {Element} node element looking from\r\n// * @return {Element} node contenteditable\r\n// */\r\n// content.getEditableParent = function (node) {\r\n//\r\n// while (node && node.contentEditable != 'true') {\r\n//\r\n// node = node.parentNode;\r\n//\r\n// }\r\n//\r\n// return node;\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Clear editors content\r\n// *\r\n// * @param {Boolean} all — if true, delete all article data (content, id, etc.)\r\n// */\r\n// content.clear = function (all) {\r\n//\r\n// editor.nodes.redactor.innerHTML = '';\r\n// editor.content.sync();\r\n// editor.ui.saveInputs();\r\n// if (all) {\r\n//\r\n// editor.state.blocks = {};\r\n//\r\n// } else if (editor.state.blocks) {\r\n//\r\n// editor.state.blocks.items = [];\r\n//\r\n// }\r\n//\r\n// editor.content.currentNode = null;\r\n//\r\n// };\r\n//\r\n// /**\r\n// *\r\n// * Load new data to editor\r\n// * If editor is not empty, just append articleData.items\r\n// *\r\n// * @param articleData.items\r\n// */\r\n// content.load = function (articleData) {\r\n//\r\n// var currentContent = Object.assign({}, editor.state.blocks);\r\n//\r\n// editor.content.clear();\r\n//\r\n// if (!Object.keys(currentContent).length) {\r\n//\r\n// editor.state.blocks = articleData;\r\n//\r\n// } else if (!currentContent.items) {\r\n//\r\n// currentContent.items = articleData.items;\r\n// editor.state.blocks = currentContent;\r\n//\r\n// } else {\r\n//\r\n// currentContent.items = currentContent.items.concat(articleData.items);\r\n// editor.state.blocks = currentContent;\r\n//\r\n// }\r\n//\r\n// editor.renderer.makeBlocksFromData();\r\n//\r\n// };\r\n//\r\n// return content;\r\n//\r\n// })({});","/**\r\n * Codex Editor Destroyer module\r\n *\r\n * @auhor Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = function (destroyer) {\n let editor = codex.editor;\r\n\r\n destroyer.removeNodes = function () {\n editor.nodes.wrapper.remove();\r\n editor.nodes.notifications.remove();\n };\r\n\r\n destroyer.destroyPlugins = function () {\n for (var tool in editor.tools) {\n if (typeof editor.tools[tool].destroy === 'function') {\n editor.tools[tool].destroy();\n }\n }\n };\r\n\r\n destroyer.destroyScripts = function () {\n var scripts = document.getElementsByTagName('SCRIPT');\r\n\r\n for (var i = 0; i < scripts.length; i++) {\n if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n scripts[i].remove();\r\n i--;\n }\n }\n };\r\n\r\n\r\n /**\r\n * Delete editor data from webpage.\r\n * You should send settings argument with boolean flags:\r\n * @param settings.ui- remove redactor event listeners and DOM nodes\r\n * @param settings.scripts - remove redactor scripts from DOM\r\n * @param settings.plugins - remove plugin's objects\r\n * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\r\n * }\r\n *\r\n */\r\n destroyer.destroy = function (settings) {\n if (!settings || typeof settings !== 'object') {\n return;\n }\r\n\r\n if (settings.ui) {\n destroyer.removeNodes();\r\n editor.listeners.removeAll();\n }\r\n\r\n if (settings.scripts) {\n destroyer.destroyScripts();\n }\r\n\r\n if (settings.plugins) {\n destroyer.destroyPlugins();\n }\r\n\r\n if (settings.ui && settings.scripts && settings.core) {\n delete codex.editor;\n }\n };\r\n\r\n return destroyer;\n}({});","/**\r\n * Codex Editor Notification Module\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = (function (notifications) {\n let editor = codex.editor;\r\n\r\n var queue = [];\r\n\r\n var addToQueue = function (settings) {\n queue.push(settings);\r\n\r\n var index = 0;\r\n\r\n while ( index < queue.length && queue.length > 5) {\n if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n index++;\r\n continue;\n }\r\n\r\n queue[index].close();\r\n queue.splice(index, 1);\n }\n };\r\n\r\n notifications.createHolder = function () {\n var holder = editor.draw.node('DIV', 'cdx-notifications-block');\r\n\r\n editor.nodes.notifications = document.body.appendChild(holder);\r\n\r\n return holder;\n };\r\n\r\n\r\n /**\r\n * Error notificator. Shows block with message\r\n * @protected\r\n */\r\n notifications.errorThrown = function (errorMsg, event) {\n editor.notifications.notification({message: 'This action is not available currently', type: event.type});\n };\r\n\r\n /**\r\n *\r\n * Appends notification\r\n *\r\n * settings = {\r\n * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\r\n * message - notification message\r\n * okMsg - confirm button text (default - 'Ok')\r\n * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\r\n * confirm - function-handler for ok button click\r\n * cancel - function-handler for cancel button click. Only for confirm and prompt types\r\n * time - time (in seconds) after which notification will close (default - 10s)\r\n * }\r\n *\r\n * @param settings\r\n */\r\n notifications.notification = function (constructorSettings) {\n /** Private vars and methods */\r\n var notification = null,\r\n cancel = null,\r\n type = null,\r\n confirm = null,\r\n inputField = null;\r\n\r\n var confirmHandler = function () {\n close();\r\n\r\n if (typeof confirm !== 'function' ) {\n return;\n }\r\n\r\n if (type == 'prompt') {\n confirm(inputField.value);\r\n return;\n }\r\n\r\n confirm();\n };\r\n\r\n var cancelHandler = function () {\n close();\r\n\r\n if (typeof cancel !== 'function' ) {\n return;\n }\r\n\r\n cancel();\n };\r\n\r\n\r\n /** Public methods */\r\n function create(settings) {\n if (!(settings && settings.message)) {\n editor.core.log('Can\\'t create notification. Message is missed');\r\n return;\n }\r\n\r\n settings.type = settings.type || 'alert';\r\n settings.time = settings.time*1000 || 10000;\r\n\r\n var wrapper = editor.draw.node('DIV', 'cdx-notification'),\r\n message = editor.draw.node('DIV', 'cdx-notification__message'),\r\n input = editor.draw.node('INPUT', 'cdx-notification__input'),\r\n okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\r\n cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\r\n\r\n message.textContent = settings.message;\r\n okBtn.textContent = settings.okMsg || 'ОК';\r\n cancelBtn.textContent = settings.cancelMsg || 'Отмена';\r\n\r\n editor.listeners.add(okBtn, 'click', confirmHandler);\r\n editor.listeners.add(cancelBtn, 'click', cancelHandler);\r\n\r\n wrapper.appendChild(message);\r\n\r\n if (settings.type == 'prompt') {\n wrapper.appendChild(input);\n }\r\n\r\n wrapper.appendChild(okBtn);\r\n\r\n if (settings.type == 'prompt' || settings.type == 'confirm') {\n wrapper.appendChild(cancelBtn);\n }\r\n\r\n wrapper.classList.add('cdx-notification-' + settings.type);\r\n wrapper.dataset.type = settings.type;\r\n\r\n notification = wrapper;\r\n type = settings.type;\r\n confirm = settings.confirm;\r\n cancel = settings.cancel;\r\n inputField = input;\r\n\r\n if (settings.type != 'prompt' && settings.type != 'confirm') {\n window.setTimeout(close, settings.time);\n }\n };\r\n\r\n /**\r\n * Show notification block\r\n */\r\n function send() {\n editor.nodes.notifications.appendChild(notification);\r\n inputField.focus();\r\n\r\n editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\r\n\r\n window.setTimeout(function () {\n editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n }, 100);\r\n\r\n addToQueue({type: type, close: close});\n };\r\n\r\n /**\r\n * Remove notification block\r\n */\r\n function close() {\n notification.remove();\n };\r\n\r\n\r\n if (constructorSettings) {\n create(constructorSettings);\r\n send();\n }\r\n\r\n return {\r\n create: create,\r\n send: send,\r\n close: close\r\n };\n };\r\n\r\n notifications.clear = function () {\n editor.nodes.notifications.innerHTML = '';\r\n queue = [];\n };\r\n\r\n return notifications;\n})({});","/**\r\n * Codex Editor Parser Module\r\n *\r\n * @author Codex Team\r\n * @version 1.1\r\n */\r\n\r\nmodule.exports = (function (parser) {\n let editor = codex.editor;\r\n\r\n /** inserting text */\r\n parser.insertPastedContent = function (blockType, tag) {\n editor.content.insertBlock({\r\n type : blockType.type,\r\n block : blockType.render({\r\n text : tag.innerHTML\r\n })\r\n });\n };\r\n\r\n /**\r\n * Check DOM node for display style: separated block or child-view\r\n */\r\n parser.isFirstLevelBlock = function (node) {\n return node.nodeType == editor.core.nodeTypes.TAG &&\r\n node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n };\r\n\r\n return parser;\n})({});\r\n","/**\r\n * Codex Editor Paste module\r\n *\r\n * @author Codex Team\r\n * @version 1.1.1\r\n */\r\n\r\nmodule.exports = function (paste) {\n let editor = codex.editor;\r\n\r\n var patterns = [];\r\n\r\n paste.prepare = function () {\n var tools = editor.tools;\r\n\r\n for (var tool in tools) {\n if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n continue;\n }\r\n\r\n tools[tool].renderOnPastePatterns.map(function (pattern) {\n patterns.push(pattern);\n });\n }\r\n\r\n return Promise.resolve();\n };\r\n\r\n /**\r\n * Saves data\r\n * @param event\r\n */\r\n paste.pasted = function (event) {\n var clipBoardData = event.clipboardData || window.clipboardData,\r\n content = clipBoardData.getData('Text');\r\n\r\n var result = analize(content);\r\n\r\n if (result) {\n event.preventDefault();\r\n event.stopImmediatePropagation();\n }\r\n\r\n return result;\n };\r\n\r\n /**\r\n * Analizes pated string and calls necessary method\r\n */\r\n\r\n var analize = function (string) {\n var result = false,\r\n content = editor.content.currentNode,\r\n plugin = content.dataset.tool;\r\n\r\n patterns.map( function (pattern) {\n var execArray = pattern.regex.exec(string),\r\n match = execArray && execArray[0];\r\n\r\n if ( match && match === string.trim()) {\n /** current block is not empty */\r\n if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {\n pasteToNewBlock_();\n }\r\n\r\n pattern.callback(string, pattern);\r\n result = true;\n }\n });\r\n\r\n return result;\n };\r\n\r\n var pasteToNewBlock_ = function () {\n /** Create new initial block */\r\n editor.content.insertBlock({\r\n\r\n type : editor.settings.initialBlockPlugin,\r\n block : editor.tools[editor.settings.initialBlockPlugin].render({\r\n text : ''\r\n })\r\n\r\n }, false);\n };\r\n\r\n /**\r\n * This method prevents default behaviour.\r\n *\r\n * @param {Object} event\r\n * @protected\r\n *\r\n * @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.\r\n * Firstly, we need to memorize the caret position. We can do that by getting the range of selection.\r\n * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node\r\n */\r\n paste.blockPasteCallback = function (event) {\n if (!needsToHandlePasteEvent(event.target)) {\n return;\n }\r\n\r\n /** Prevent default behaviour */\r\n event.preventDefault();\r\n\r\n /** get html pasted data - dirty data */\r\n var htmlData = event.clipboardData.getData('text/html'),\r\n plainData = event.clipboardData.getData('text/plain');\r\n\r\n /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/\r\n var paragraphs = editor.draw.node('DIV', '', {}),\r\n cleanData,\r\n wrappedData;\r\n\r\n /** Create fragment, that we paste to range after proccesing */\r\n cleanData = editor.sanitizer.clean(htmlData);\r\n\r\n /**\r\n * We wrap pasted text with

    tags to split it logically\r\n * @type {string}\r\n */\r\n wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData);\r\n paragraphs.innerHTML = wrappedData;\r\n\r\n /**\r\n * If there only one paragraph, just insert in at the caret location\r\n */\r\n if (paragraphs.childNodes.length == 1) {\n emulateUserAgentBehaviour(paragraphs.firstChild);\r\n return;\n }\r\n\r\n insertPastedParagraphs(paragraphs.childNodes);\n };\r\n\r\n /**\r\n * Checks if we should handle paste event on block\r\n * @param block\r\n *\r\n * @return {boolean}\r\n */\r\n var needsToHandlePasteEvent = function (block) {\n /** If area is input or textarea then allow default behaviour */\r\n if ( editor.core.isNativeInput(block) ) {\n return false;\n }\r\n\r\n var editableParent = editor.content.getEditableParent(block);\r\n\r\n /** Allow paste when event target placed in Editable element */\r\n if (!editableParent) {\n return false;\n }\r\n\r\n return true;\n };\r\n\r\n /**\r\n * Inserts new initial plugin blocks with data in paragraphs\r\n *\r\n * @param {Array} paragraphs - array of paragraphs (

    ) whit content, that should be inserted\r\n */\r\n var insertPastedParagraphs = function (paragraphs) {\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin,\r\n currentNode = editor.content.currentNode;\r\n\r\n\r\n paragraphs.forEach(function (paragraph) {\n /** Don't allow empty paragraphs */\r\n if (editor.core.isBlockEmpty(paragraph)) {\n return;\n }\r\n\r\n editor.content.insertBlock({\r\n type : NEW_BLOCK_TYPE,\r\n block : editor.tools[NEW_BLOCK_TYPE].render({\r\n text : paragraph.innerHTML\r\n })\r\n });\r\n\r\n editor.caret.inputIndex++;\n });\r\n\r\n editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1);\r\n\r\n\r\n /**\r\n * If there was no data in working node, remove it\r\n */\r\n if (editor.core.isBlockEmpty(currentNode)) {\n currentNode.remove();\r\n editor.ui.saveInputs();\n }\n };\r\n\r\n /**\r\n * Inserts node content at the caret position\r\n *\r\n * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location\r\n */\r\n var emulateUserAgentBehaviour = function (node) {\n var newNode;\r\n\r\n if (node.childElementCount) {\n newNode = document.createDocumentFragment();\r\n\r\n node.childNodes.forEach(function (current) {\n if (!editor.core.isDomNode(current) && current.data.trim() === '') {\n return;\n }\r\n\r\n newNode.appendChild(current.cloneNode(true));\n });\n } else {\n newNode = document.createTextNode(node.textContent);\n }\r\n\r\n editor.caret.insertNode(newNode);\n };\r\n\r\n\r\n return paste;\n}({});","/**\r\n *\r\n * Codex.Editor Transport Module\r\n *\r\n * @copyright 2017 Codex-Team\r\n * @version 1.2.0\r\n */\r\n\r\nmodule.exports = (function (transport) {\n let editor = codex.editor;\r\n\r\n\r\n /**\r\n * @private {Object} current XmlHttpRequest instance\r\n */\r\n var currentRequest = null;\r\n\r\n\r\n /**\r\n * @type {null} | {DOMElement} input - keeps input element in memory\r\n */\r\n transport.input = null;\r\n\r\n /**\r\n * @property {Object} arguments - keep plugin settings and defined callbacks\r\n */\r\n transport.arguments = null;\r\n\r\n /**\r\n * Prepares input element where will be files\r\n */\r\n transport.prepare = function () {\n let input = editor.draw.node( 'INPUT', '', { type : 'file' } );\r\n\r\n editor.listeners.add(input, 'change', editor.transport.fileSelected);\r\n editor.transport.input = input;\n };\r\n\r\n /** Clear input when files is uploaded */\r\n transport.clearInput = function () {\n /** Remove old input */\r\n transport.input = null;\r\n\r\n /** Prepare new one */\r\n transport.prepare();\n };\r\n\r\n /**\r\n * Callback for file selection\r\n * @param {Event} event\r\n */\r\n transport.fileSelected = function () {\n var input = this,\r\n i,\r\n files = input.files,\r\n formData = new FormData();\r\n\r\n if (editor.transport.arguments.multiple === true) {\n for ( i = 0; i < files.length; i++) {\n formData.append('files[]', files[i], files[i].name);\n }\n } else {\n formData.append('files', files[0], files[0].name);\n }\r\n\r\n currentRequest = editor.core.ajax({\r\n type : 'POST',\r\n data : formData,\r\n url : editor.transport.arguments.url,\r\n beforeSend : editor.transport.arguments.beforeSend,\r\n success : editor.transport.arguments.success,\r\n error : editor.transport.arguments.error,\r\n progress : editor.transport.arguments.progress\r\n });\r\n\r\n /** Clear input */\r\n transport.clearInput();\n };\r\n\r\n /**\r\n * Use plugin callbacks\r\n * @protected\r\n *\r\n * @param {Object} args - can have :\r\n * @param {String} args.url - fetch URL\r\n * @param {Function} args.beforeSend - function calls before sending ajax\r\n * @param {Function} args.success - success callback\r\n * @param {Function} args.error - on error handler\r\n * @param {Function} args.progress - xhr onprogress handler\r\n * @param {Boolean} args.multiple - allow select several files\r\n * @param {String} args.accept - adds accept attribute\r\n */\r\n transport.selectAndUpload = function (args) {\n transport.arguments = args;\r\n\r\n if ( args.multiple === true) {\n transport.input.setAttribute('multiple', 'multiple');\n }\r\n\r\n if ( args.accept ) {\n transport.input.setAttribute('accept', args.accept);\n }\r\n\r\n transport.input.click();\n };\r\n\r\n transport.abort = function () {\n currentRequest.abort();\r\n\r\n currentRequest = null;\n };\r\n\r\n return transport;\n})({});","/**\r\n * @class BlocksAPI\r\n * provides with methods working with Block\r\n */\r\nexport default class BlocksAPI extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorsConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * Available methods\r\n * @return {IBlocksAPI}\r\n */\r\n get methods() {\r\n return {\r\n clear: () => this.clear(),\r\n render: (data) => this.render(data),\r\n delete: () => this.delete(),\r\n swap: (fromIndex, toIndex) => this.swap(fromIndex, toIndex),\r\n getBlockByIndex: (index) => this.getBlockByIndex(index),\r\n getCurrentBlockIndex: () => this.getCurrentBlockIndex(),\r\n };\r\n }\r\n /**\r\n * Returns current block index\r\n * @return {number}\r\n */\r\n getCurrentBlockIndex() {\r\n return this.Editor.BlockManager.currentBlockIndex;\r\n }\r\n /**\r\n * Returns Current Block\r\n * @param {Number} index\r\n *\r\n * @return {Object}\r\n */\r\n getBlockByIndex(index) {\r\n return this.Editor.BlockManager.getBlockByIndex(index);\r\n }\r\n /**\r\n * Call Block Manager method that swap Blocks\r\n * @param {number} fromIndex - position of first Block\r\n * @param {number} toIndex - position of second Block\r\n */\r\n swap(fromIndex, toIndex) {\r\n this.Editor.BlockManager.swap(fromIndex, toIndex);\r\n /**\r\n * Move toolbar\r\n * DO not close the settings\r\n */\r\n this.Editor.Toolbar.move(false);\r\n }\r\n /**\r\n * Deletes Block\r\n * @param blockIndex\r\n */\r\n delete(blockIndex) {\r\n this.Editor.BlockManager.removeBlock(blockIndex);\r\n /**\r\n * in case of last block deletion\r\n * Insert new initial empty block\r\n */\r\n if (this.Editor.BlockManager.blocks.length === 0) {\r\n this.Editor.BlockManager.insert();\r\n }\r\n /**\r\n * In case of deletion first block we need to set caret to the current Block\r\n */\r\n if (this.Editor.BlockManager.currentBlockIndex === 0) {\r\n this.Editor.Caret.setToBlock(this.Editor.BlockManager.currentBlock);\r\n }\r\n else {\r\n if (this.Editor.Caret.navigatePrevious(true)) {\r\n this.Editor.Toolbar.close();\r\n }\r\n }\r\n }\r\n /**\r\n * Clear Editor's area\r\n */\r\n clear() {\r\n this.Editor.BlockManager.clear(true);\r\n }\r\n /**\r\n * Fills Editor with Blocks data\r\n * @param {IInputOutputData} data — Saved Editor data\r\n */\r\n render(data) {\r\n this.Editor.BlockManager.clear();\r\n this.Editor.Renderer.render(data.items);\r\n }\r\n}\r\n","/**\r\n * @class EventsAPI\r\n * provides with methods working with Toolbar\r\n */\r\nexport default class EventsAPI extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorsConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * Available methods\r\n * @return {IEventsAPI}\r\n */\r\n get methods() {\r\n return {\r\n emit: (eventName, data) => this.emit(eventName, data),\r\n off: (eventName, callback) => this.off(eventName, callback),\r\n on: (eventName, callback) => this.on(eventName, callback),\r\n };\r\n }\r\n /**\r\n * Subscribe on Events\r\n * @param {String} eventName\r\n * @param {Function} callback\r\n */\r\n on(eventName, callback) {\r\n this.Editor.Events.on(eventName, callback);\r\n }\r\n /**\r\n * Emit event with data\r\n * @param {String} eventName\r\n * @param {Object} data\r\n */\r\n emit(eventName, data) {\r\n this.Editor.Events.emit(eventName, data);\r\n }\r\n /**\r\n * Unsubscribe from Event\r\n * @param {String} eventName\r\n * @param {Function} callback\r\n */\r\n off(eventName, callback) {\r\n this.Editor.Events.off(eventName, callback);\r\n }\r\n}\r\n","/**\r\n * @class API\r\n * Provides with methods working with DOM Listener\r\n */\r\nexport default class ListenerAPI extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorsConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * Available methods\r\n * @return {IToolbarAPI}\r\n */\r\n get methods() {\r\n return {\r\n on: (element, eventType, handler, useCapture) => this.on(element, eventType, handler, useCapture),\r\n off: (element, eventType, handler) => this.off(element, eventType, handler),\r\n };\r\n }\r\n /**\r\n * adds DOM event listener\r\n *\r\n * @param {HTMLElement} element\r\n * @param {string} eventType\r\n * @param {() => void} handler\r\n * @param {boolean} useCapture\r\n */\r\n on(element, eventType, handler, useCapture) {\r\n this.Editor.Listeners.on(element, eventType, handler, useCapture);\r\n }\r\n /**\r\n * Removes DOM listener from element\r\n *\r\n * @param element\r\n * @param eventType\r\n * @param handler\r\n */\r\n off(element, eventType, handler) {\r\n this.Editor.Listeners.off(element, eventType, handler);\r\n }\r\n}\r\n","/**\r\n * @class API\r\n * Provides CodeX Editor Sanitizer that allows developers to clean their HTML\r\n */\r\nexport default class SanitizerAPI extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorsConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * Available methods\r\n * @return {ISanitizerAPI}\r\n */\r\n get methods() {\r\n return {\r\n clean: (taintString, config) => this.clean(taintString, config),\r\n };\r\n }\r\n clean(taintString, config) {\r\n return this.Editor.Sanitizer.clean(taintString, config);\r\n }\r\n}\r\n","/**\r\n * @class SaverAPI\r\n * provides with methods to save data\r\n */\r\nexport default class SaverAPI extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorsConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * Available methods\r\n * @return {ISaverAPI}\r\n */\r\n get methods() {\r\n return {\r\n save: () => this.save(),\r\n };\r\n }\r\n /**\r\n * Return Editor's data\r\n */\r\n save() {\r\n return this.Editor.Saver.save();\r\n }\r\n}\r\n","import Selection from '../selection';\r\n/**\r\n * @class API\r\n * Provides with methods working with Selection\r\n */\r\nexport default class SelectionAPI extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorsConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * Available methods\r\n * @return {ISelectionAPI}\r\n */\r\n get methods() {\r\n return {\r\n findParentTag: (tagName, className) => this.findParentTag(tagName, className),\r\n expandToTag: (node) => this.expandToTag(node),\r\n };\r\n }\r\n /**\r\n * Looks ahead from selection and find passed tag with class name\r\n * @param {string} tagName - tag to find\r\n * @param {string} className - tag's class name\r\n * @return {HTMLElement|null}\r\n */\r\n findParentTag(tagName, className) {\r\n return new Selection().findParentTag(tagName, className);\r\n }\r\n /**\r\n * Expand selection to passed tag\r\n * @param {HTMLElement} node - tag that should contain selection\r\n */\r\n expandToTag(node) {\r\n new Selection().expandToTag(node);\r\n }\r\n}\r\n","/**\r\n * @class ToolbarsAPI\r\n * provides with methods working with Toolbar\r\n */\r\nexport default class ToolbarAPI extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorsConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * Available methods\r\n * @return {IToolbarAPI}\r\n */\r\n get methods() {\r\n return {\r\n close: () => this.close(),\r\n open: () => this.open(),\r\n };\r\n }\r\n /**\r\n * Open toolbar\r\n */\r\n open() {\r\n this.Editor.Toolbar.open();\r\n }\r\n /**\r\n * Close toolbar and all included elements\r\n */\r\n close() {\r\n this.Editor.Toolbar.close();\r\n }\r\n}\r\n","/**\r\n * @class API\r\n */\r\nexport default class API extends Module {\r\n /**\r\n * Save Editor config. API provides passed configuration to the Blocks\r\n * @param {EditorConfig} config\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n get methods() {\r\n return {\r\n blocks: this.Editor.BlocksAPI.methods,\r\n caret: {},\r\n events: this.Editor.EventsAPI.methods,\r\n sanitizer: this.Editor.SanitizerAPI.methods,\r\n saver: this.Editor.SaverAPI.methods,\r\n selection: this.Editor.SelectionAPI.methods,\r\n listener: this.Editor.ListenerAPI.methods,\r\n toolbar: this.Editor.ToolbarAPI.methods,\r\n };\r\n }\r\n}\r\n","export default class BlockEvents extends Module {\r\n /**\r\n * @constructor\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n }\r\n /**\r\n * All keydowns on Block\r\n * @param {KeyboardEvent} event - keydown\r\n */\r\n keydown(event) {\r\n switch (event.keyCode) {\r\n case _.keyCodes.BACKSPACE:\r\n this.backspace(event);\r\n break;\r\n case _.keyCodes.ENTER:\r\n this.enter(event);\r\n break;\r\n case _.keyCodes.DOWN:\r\n case _.keyCodes.RIGHT:\r\n this.arrowRightAndDownPressed();\r\n break;\r\n case _.keyCodes.UP:\r\n case _.keyCodes.LEFT:\r\n this.arrowLeftAndUpPressed();\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n /**\r\n * Key up on Block:\r\n * - shows Inline Toolbar if something selected\r\n */\r\n keyup(event) {\r\n this.Editor.InlineToolbar.handleShowingEvent(event);\r\n }\r\n /**\r\n * Mouse up on Block:\r\n * - shows Inline Toolbar if something selected\r\n */\r\n mouseUp(event) {\r\n this.Editor.InlineToolbar.handleShowingEvent(event);\r\n }\r\n /**\r\n * ENTER pressed on block\r\n * @param {KeyboardEvent} event - keydown\r\n */\r\n enter(event) {\r\n const currentBlock = this.Editor.BlockManager.currentBlock, toolsConfig = this.config.toolsConfig[currentBlock.name];\r\n /**\r\n * Don't handle Enter keydowns when Tool sets enableLineBreaks to true.\r\n * Uses for Tools like where line breaks should be handled by default behaviour.\r\n */\r\n if (toolsConfig && toolsConfig[this.Editor.Tools.apiSettings.IS_ENABLED_LINE_BREAKS]) {\r\n return;\r\n }\r\n /**\r\n * Allow to create linebreaks by Shift+Enter\r\n */\r\n if (event.shiftKey) {\r\n return;\r\n }\r\n /**\r\n * Split the Current Block into two blocks\r\n */\r\n this.Editor.BlockManager.split();\r\n /**\r\n * Renew local current node after split\r\n */\r\n const newCurrent = this.Editor.BlockManager.currentBlock;\r\n this.Editor.Toolbar.move();\r\n this.Editor.Toolbar.open();\r\n if (this.Editor.Tools.isInitial(newCurrent.tool) && newCurrent.isEmpty) {\r\n this.Editor.Toolbar.plusButton.show();\r\n }\r\n event.preventDefault();\r\n }\r\n /**\r\n * Handle backspace keydown on Block\r\n * @param {KeyboardEvent} event - keydown\r\n */\r\n backspace(event) {\r\n const BM = this.Editor.BlockManager;\r\n const isFirstBlock = BM.currentBlockIndex === 0, canMergeBlocks = this.Editor.Caret.isAtStart && !isFirstBlock;\r\n if (!canMergeBlocks) {\r\n return;\r\n }\r\n // preventing browser default behaviour\r\n event.preventDefault();\r\n const targetBlock = BM.getBlockByIndex(BM.currentBlockIndex - 1), blockToMerge = BM.currentBlock;\r\n /**\r\n * Blocks that can be merged:\r\n * 1) with the same Name\r\n * 2) Tool has 'merge' method\r\n *\r\n * other case will handle as usual ARROW LEFT behaviour\r\n */\r\n if (blockToMerge.name !== targetBlock.name || !targetBlock.mergeable) {\r\n if (this.Editor.Caret.navigatePrevious()) {\r\n this.Editor.Toolbar.close();\r\n }\r\n }\r\n const setCaretToTheEnd = !targetBlock.isEmpty;\r\n BM.mergeBlocks(targetBlock, blockToMerge)\r\n .then(() => {\r\n // @todo figure out without timeout\r\n window.setTimeout(() => {\r\n // set caret to the block without offset at the end\r\n this.Editor.Caret.setToBlock(BM.currentBlock, 0, setCaretToTheEnd);\r\n this.Editor.Toolbar.close();\r\n }, 10);\r\n });\r\n }\r\n /**\r\n * Handle right and down keyboard keys\r\n */\r\n arrowRightAndDownPressed() {\r\n this.Editor.Caret.navigateNext();\r\n this.Editor.Toolbar.close();\r\n }\r\n /**\r\n * Handle left and up keyboard keys\r\n */\r\n arrowLeftAndUpPressed() {\r\n this.Editor.Caret.navigatePrevious();\r\n this.Editor.Toolbar.close();\r\n }\r\n}\r\n","/**\r\n * @class BlockManager\r\n * @classdesc Manage editor`s blocks storage and appearance\r\n *\r\n * @module BlockManager\r\n *\r\n * @version 2.0.0\r\n */\r\n\r\nimport Block from '../block';\r\n\r\n/**\r\n * @typedef {BlockManager} BlockManager\r\n * @property {Number} currentBlockIndex - Index of current working block\r\n * @property {Proxy} _blocks - Proxy for Blocks instance {@link Blocks}\r\n */\r\nexport default class BlockManager extends Module {\r\n /**\r\n * @constructor\r\n * @param {EditorConfig} config\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n /**\r\n * Proxy for Blocks instance {@link Blocks}\r\n *\r\n * @type {Proxy}\r\n * @private\r\n */\r\n this._blocks = null;\r\n\r\n /**\r\n * Index of current working block\r\n *\r\n * @type {number}\r\n * @private\r\n */\r\n this.currentBlockIndex = -1;\r\n }\r\n\r\n /**\r\n * Should be called after Editor.UI preparation\r\n * Define this._blocks property\r\n *\r\n * @returns {Promise}\r\n */\r\n prepare() {\r\n return new Promise(resolve => {\r\n let blocks = new Blocks(this.Editor.UI.nodes.redactor);\r\n\r\n /**\r\n * We need to use Proxy to overload set/get [] operator.\r\n * So we can use array-like syntax to access blocks\r\n *\r\n * @example\r\n * this._blocks[0] = new Block(...);\r\n *\r\n * block = this._blocks[0];\r\n *\r\n * @todo proxy the enumerate method\r\n *\r\n * @type {Proxy}\r\n * @private\r\n */\r\n this._blocks = new Proxy(blocks, {\r\n set: Blocks.set,\r\n get: Blocks.get\r\n });\r\n\r\n resolve();\r\n });\r\n }\r\n\r\n /**\r\n * Creates Block instance by tool name\r\n *\r\n * @param {String} toolName - tools passed in editor config {@link EditorConfig#tools}\r\n * @param {Object} data - constructor params\r\n * @param {Object} settings - block settings\r\n *\r\n * @return {Block}\r\n */\r\n composeBlock(toolName, data, settings) {\r\n let toolInstance = this.Editor.Tools.construct(toolName, data),\r\n block = new Block(toolName, toolInstance, settings, this.Editor.API.methods);\r\n\r\n this.bindEvents(block);\r\n /**\r\n * Apply callback before inserting html\r\n */\r\n block.call('appendCallback', {});\r\n\r\n return block;\r\n }\r\n\r\n /**\r\n * Bind Events\r\n * @param {Object} block\r\n */\r\n bindEvents(block) {\r\n this.Editor.Listeners.on(block.pluginsContent, 'keydown', (event) => this.Editor.BlockEvents.keydown(event));\r\n this.Editor.Listeners.on(block.pluginsContent, 'mouseup', (event) => this.Editor.BlockEvents.mouseUp(event));\r\n this.Editor.Listeners.on(block.pluginsContent, 'keyup', (event) => this.Editor.BlockEvents.keyup(event));\r\n }\r\n\r\n /**\r\n * Insert new block into _blocks\r\n *\r\n * @param {String} toolName — plugin name, by default method inserts initial block type\r\n * @param {Object} data — plugin data\r\n * @param {Object} settings - default settings\r\n *\r\n * @return {Block}\r\n */\r\n insert(toolName = this.config.initialBlock, data = {}, settings = {}) {\r\n let block = this.composeBlock(toolName, data, settings);\r\n\r\n this._blocks[++this.currentBlockIndex] = block;\r\n this.Editor.Caret.setToBlock(block);\r\n\r\n return block;\r\n }\r\n\r\n /**\r\n * Merge two blocks\r\n * @param {Block} targetBlock - previous block will be append to this block\r\n * @param {Block} blockToMerge - block that will be merged with target block\r\n *\r\n * @return {Promise} - the sequence that can be continued\r\n */\r\n mergeBlocks(targetBlock, blockToMerge) {\r\n let blockToMergeIndex = this._blocks.indexOf(blockToMerge);\r\n\r\n return Promise.resolve()\r\n .then( () => {\r\n if (blockToMerge.isEmpty) {\r\n return;\r\n }\r\n\r\n return blockToMerge.data\r\n .then((blockToMergeInfo) => {\r\n targetBlock.mergeWith(blockToMergeInfo.data);\r\n });\r\n })\r\n .then( () => {\r\n this.removeBlock(blockToMergeIndex);\r\n this.currentBlockIndex = this._blocks.indexOf(targetBlock);\r\n });\r\n }\r\n\r\n /**\r\n * Remove block with passed index or remove last\r\n * @param {Number|null} index\r\n */\r\n removeBlock(index) {\r\n if (!index) {\r\n index = this.currentBlockIndex;\r\n }\r\n this._blocks.remove(index);\r\n }\r\n\r\n /**\r\n * Split current Block\r\n * 1. Extract content from Caret position to the Block`s end\r\n * 2. Insert a new Block below current one with extracted content\r\n */\r\n split() {\r\n let extractedFragment = this.Editor.Caret.extractFragmentFromCaretPosition(),\r\n wrapper = $.make('div');\r\n\r\n wrapper.append(extractedFragment);\r\n\r\n /**\r\n * @todo make object in accordance with Tool\r\n */\r\n let data = {\r\n text: $.isEmpty(wrapper) ? '' : wrapper.innerHTML,\r\n };\r\n\r\n /**\r\n * Renew current Block\r\n * @type {Block}\r\n */\r\n const blockInserted = this.insert(this.config.initialBlock, data);\r\n\r\n this.currentNode = blockInserted.pluginsContent;\r\n }\r\n\r\n /**\r\n * Replace current working block\r\n *\r\n * @param {String} toolName — plugin name\r\n * @param {Object} data — plugin data\r\n */\r\n replace(toolName, data = {}) {\r\n let block = this.composeBlock(toolName, data);\r\n\r\n this._blocks.insert(this.currentBlockIndex, block, true);\r\n }\r\n\r\n /**\r\n * returns last Block\r\n * @return {Block}\r\n */\r\n get lastBlock() {\r\n return this._blocks[this._blocks.length - 1];\r\n }\r\n\r\n /**\r\n * Returns Block by passed index\r\n * @param {Number} index\r\n * @return {Block}\r\n */\r\n getBlockByIndex(index) {\r\n return this._blocks[index];\r\n }\r\n\r\n /**\r\n * Get Block instance by html element\r\n * @param {Node} element\r\n * @returns {Block}\r\n */\r\n getBlock(element) {\r\n if (!$.isElement(element)) {\r\n element = element.parentNode;\r\n }\r\n\r\n let nodes = this._blocks.nodes,\r\n firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`),\r\n index = nodes.indexOf(firstLevelBlock);\r\n\r\n if (index >= 0) {\r\n return this._blocks[index];\r\n }\r\n }\r\n\r\n /**\r\n * Get current Block instance\r\n *\r\n * @return {Block}\r\n */\r\n get currentBlock() {\r\n return this._blocks[this.currentBlockIndex];\r\n }\r\n\r\n /**\r\n * Returns next Block instance\r\n * @return {Block|null}\r\n */\r\n get nextBlock() {\r\n let isLastBlock = this.currentBlockIndex === (this._blocks.length - 1);\r\n\r\n if (isLastBlock) {\r\n return null;\r\n }\r\n\r\n return this._blocks[this.currentBlockIndex + 1];\r\n }\r\n\r\n /**\r\n * Returns previous Block instance\r\n * @return {Block|null}\r\n */\r\n get previousBlock() {\r\n let isFirstBlock = this.currentBlockIndex === 0;\r\n\r\n if (isFirstBlock) {\r\n return null;\r\n }\r\n\r\n return this._blocks[this.currentBlockIndex - 1];\r\n }\r\n\r\n /**\r\n * Get working html element\r\n *\r\n * @return {HTMLElement}\r\n */\r\n get currentNode() {\r\n return this._blocks.nodes[this.currentBlockIndex];\r\n }\r\n\r\n /**\r\n * Set currentBlockIndex to passed block\r\n * @param {HTMLElement} element\r\n */\r\n set currentNode(element) {\r\n let nodes = this._blocks.nodes,\r\n firstLevelBlock = element.closest(`.${Block.CSS.wrapper}`);\r\n\r\n /**\r\n * Update current Block's index\r\n * @type {number}\r\n */\r\n this.currentBlockIndex = nodes.indexOf(firstLevelBlock);\r\n\r\n /**\r\n * Remove previous selected Block's state\r\n */\r\n this.blocks.forEach( block => block.selected = false);\r\n\r\n /**\r\n * Mark current Block as selected\r\n * @type {boolean}\r\n */\r\n this.currentBlock.selected = true;\r\n }\r\n\r\n /**\r\n * Get array of Block instances\r\n *\r\n * @returns {Block[]} {@link Blocks#array}\r\n */\r\n get blocks() {\r\n return this._blocks.array;\r\n }\r\n\r\n /**\r\n * 1) Find first-level Block from passed child Node\r\n * 2) Mark it as current\r\n *\r\n * @param {Element|Text} childNode - look ahead from this node.\r\n * @throws Error - when passed Node is not included at the Block\r\n */\r\n setCurrentBlockByChildNode(childNode) {\r\n /**\r\n * If node is Text TextNode\r\n */\r\n if (!$.isElement(childNode)) {\r\n childNode = childNode.parentNode;\r\n }\r\n\r\n let parentFirstLevelBlock = childNode.closest(`.${Block.CSS.wrapper}`);\r\n\r\n if (parentFirstLevelBlock) {\r\n this.currentNode = parentFirstLevelBlock;\r\n } else {\r\n throw new Error('Can not find a Block from this child Node');\r\n }\r\n }\r\n\r\n /**\r\n * Swap Blocks Position\r\n * @param {Number} fromIndex\r\n * @param {Number} toIndex\r\n */\r\n swap(fromIndex, toIndex) {\r\n /** Move up current Block */\r\n this._blocks.swap(fromIndex, toIndex);\r\n\r\n /** Now actual block moved up so that current block index decreased */\r\n this.currentBlockIndex = toIndex;\r\n }\r\n /**\r\n * Clears Editor\r\n * @param {boolean} needAddInitialBlock - 1) in internal calls (for example, in api.blocks.render)\r\n * we don't need to add empty initial block\r\n * 2) in api.blocks.clear we should add empty block\r\n */\r\n clear(needAddInitialBlock = false) {\r\n this._blocks.removeAll();\r\n this.currentBlockIndex = -1;\r\n\r\n if (needAddInitialBlock) {\r\n this.insert(this.config.initialBlock);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * @class Blocks\r\n * @classdesc Class to work with Block instances array\r\n *\r\n * @private\r\n *\r\n * @property {HTMLElement} workingArea — editor`s working node\r\n *\r\n */\r\nclass Blocks {\r\n /**\r\n * @constructor\r\n *\r\n * @param {HTMLElement} workingArea — editor`s working node\r\n */\r\n constructor(workingArea) {\r\n this.blocks = [];\r\n this.workingArea = workingArea;\r\n }\r\n\r\n /**\r\n * Push back new Block\r\n *\r\n * @param {Block} block\r\n */\r\n push(block) {\r\n this.blocks.push(block);\r\n this.workingArea.appendChild(block.html);\r\n }\r\n\r\n /**\r\n * Swaps blocks with indexes first and second\r\n * @param {Number} first - first block index\r\n * @param {Number} second - second block index\r\n */\r\n swap(first, second) {\r\n let secondBlock = this.blocks[second];\r\n\r\n /**\r\n * Change in DOM\r\n */\r\n $.swap(this.blocks[first].html, secondBlock.html);\r\n\r\n /**\r\n * Change in array\r\n */\r\n this.blocks[second] = this.blocks[first];\r\n this.blocks[first] = secondBlock;\r\n }\r\n\r\n /**\r\n * Insert new Block at passed index\r\n *\r\n * @param {Number} index — index to insert Block\r\n * @param {Block} block — Block to insert\r\n * @param {Boolean} replace — it true, replace block on given index\r\n */\r\n insert(index, block, replace = false) {\r\n if (!this.length) {\r\n this.push(block);\r\n return;\r\n }\r\n\r\n if (index > this.length) {\r\n index = this.length;\r\n }\r\n\r\n if (replace) {\r\n this.blocks[index].html.remove();\r\n }\r\n\r\n let deleteCount = replace ? 1 : 0;\r\n\r\n this.blocks.splice(index, deleteCount, block);\r\n\r\n if (index > 0) {\r\n let previousBlock = this.blocks[index - 1];\r\n\r\n previousBlock.html.insertAdjacentElement('afterend', block.html);\r\n } else {\r\n let nextBlock = this.blocks[index + 1];\r\n\r\n if (nextBlock) {\r\n nextBlock.html.insertAdjacentElement('beforebegin', block.html);\r\n } else {\r\n this.workingArea.appendChild(block.html);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Remove block\r\n * @param {Number|null} index\r\n */\r\n remove(index) {\r\n if (isNaN(index)) {\r\n index = this.length - 1;\r\n }\r\n\r\n this.blocks[index].html.remove();\r\n this.blocks.splice(index, 1);\r\n }\r\n\r\n /**\r\n * Remove all blocks\r\n */\r\n removeAll() {\r\n this.workingArea.innerHTML = '';\r\n this.blocks.length = 0;\r\n }\r\n\r\n /**\r\n * Insert Block after passed target\r\n *\r\n * @todo decide if this method is necessary\r\n *\r\n * @param {Block} targetBlock — target after wich Block should be inserted\r\n * @param {Block} newBlock — Block to insert\r\n */\r\n insertAfter(targetBlock, newBlock) {\r\n let index = this.blocks.indexOf(targetBlock);\r\n\r\n this.insert(index + 1, newBlock);\r\n }\r\n\r\n /**\r\n * Get Block by index\r\n *\r\n * @param {Number} index — Block index\r\n * @returns {Block}\r\n */\r\n get(index) {\r\n return this.blocks[index];\r\n }\r\n\r\n /**\r\n * Return index of passed Block\r\n *\r\n * @param {Block} block\r\n * @returns {Number}\r\n */\r\n indexOf(block) {\r\n return this.blocks.indexOf(block);\r\n }\r\n\r\n /**\r\n * Get length of Block instances array\r\n *\r\n * @returns {Number}\r\n */\r\n get length() {\r\n return this.blocks.length;\r\n }\r\n\r\n /**\r\n * Get Block instances array\r\n *\r\n * @returns {Block[]}\r\n */\r\n get array() {\r\n return this.blocks;\r\n }\r\n\r\n /**\r\n * Get blocks html elements array\r\n *\r\n * @returns {HTMLElement[]}\r\n */\r\n get nodes() {\r\n return _.array(this.workingArea.children);\r\n }\r\n\r\n /**\r\n * Proxy trap to implement array-like setter\r\n *\r\n * @example\r\n * blocks[0] = new Block(...)\r\n *\r\n * @param {Blocks} instance — Blocks instance\r\n * @param {Number|String} index — block index\r\n * @param {Block} block — Block to set\r\n * @returns {Boolean}\r\n */\r\n static set(instance, index, block) {\r\n if (isNaN(Number(index))) {\r\n return false;\r\n }\r\n\r\n instance.insert(index, block);\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Proxy trap to implement array-like getter\r\n *\r\n * @param {Blocks} instance — Blocks instance\r\n * @param {Number|String} index — Block index\r\n * @returns {Block|*}\r\n */\r\n static get(instance, index) {\r\n if (isNaN(Number(index))) {\r\n return instance[index];\r\n }\r\n\r\n return instance.get(index);\r\n }\r\n}\r\n","/**\r\n * @class Caret\r\n * @classdesc Contains methods for working Caret\r\n *\r\n * Uses Range methods to manipulate with caret\r\n *\r\n * @module Caret\r\n *\r\n * @version 2.0.0\r\n */\r\n\r\nimport Selection from '../selection';\r\n\r\n/**\r\n * @typedef {Caret} Caret\r\n */\r\nexport default class Caret extends Module {\r\n /**\r\n * @constructor\r\n */\r\n constructor({config}) {\r\n super({config});\r\n }\r\n\r\n /**\r\n * Method gets Block instance and puts caret to the text node with offset\r\n * There two ways that method applies caret position:\r\n * - first found text node: sets at the beginning, but you can pass an offset\r\n * - last found text node: sets at the end of the node. Also, you can customize the behaviour\r\n *\r\n * @param {Block} block - Block class\r\n * @param {Number} offset - caret offset regarding to the text node\r\n * @param {Boolean} atEnd - put caret at the end of the text node or not\r\n */\r\n setToBlock(block, offset = 0, atEnd = false) {\r\n let element = block.pluginsContent;\r\n\r\n /** If Element is INPUT */\r\n if ($.isNativeInput(element)) {\r\n element.focus();\r\n return;\r\n }\r\n\r\n let nodeToSet = $.getDeepestNode(element, atEnd);\r\n\r\n if (atEnd || offset > nodeToSet.length) {\r\n offset = nodeToSet.length;\r\n }\r\n\r\n /** if found deepest node is native input */\r\n if ($.isNativeInput(nodeToSet)) {\r\n nodeToSet.focus();\r\n return;\r\n }\r\n\r\n /**\r\n * @todo try to fix via Promises or use querySelectorAll to not to use timeout\r\n */\r\n _.delay( () => {\r\n this.set(nodeToSet, offset);\r\n }, 20)();\r\n\r\n this.Editor.BlockManager.currentNode = block.wrapper;\r\n }\r\n\r\n /**\r\n * Creates Document Range and sets caret to the element with offset\r\n * @param {Element} element - target node.\r\n * @param {Number} offset - offset\r\n */\r\n set( element, offset = 0) {\r\n let range = document.createRange(),\r\n selection = Selection.get();\r\n\r\n range.setStart(element, offset);\r\n range.setEnd(element, offset);\r\n\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n };\r\n\r\n /**\r\n * Set Caret to the last Block\r\n * If last block is not empty, append another empty block\r\n */\r\n setToTheLastBlock() {\r\n let lastBlock = this.Editor.BlockManager.lastBlock;\r\n\r\n if (!lastBlock) return;\r\n\r\n /**\r\n * If last block is empty and it is an initialBlock, set to that.\r\n * Otherwise, append new empty block and set to that\r\n */\r\n if (lastBlock.isEmpty) {\r\n this.setToBlock(lastBlock);\r\n } else {\r\n this.Editor.BlockManager.insert(this.config.initialBlock);\r\n }\r\n }\r\n\r\n /**\r\n * Extract content fragment of current Block from Caret position to the end of the Block\r\n */\r\n extractFragmentFromCaretPosition() {\r\n let selection = Selection.get();\r\n\r\n if (selection.rangeCount) {\r\n let selectRange = selection.getRangeAt(0),\r\n blockElem = this.Editor.BlockManager.currentBlock.pluginsContent;\r\n\r\n selectRange.deleteContents();\r\n\r\n if (blockElem) {\r\n let range = selectRange.cloneRange(true);\r\n\r\n range.selectNodeContents(blockElem);\r\n range.setStart(selectRange.endContainer, selectRange.endOffset);\r\n return range.extractContents();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get all first-level (first child of [contenteditabel]) siblings from passed node\r\n * Then you can check it for emptiness\r\n *\r\n * @example\r\n *
    \r\n *\r\n * @return {Element[]}\r\n */\r\n getHigherLevelSiblings(from, direction ) {\r\n let current = from,\r\n siblings = [];\r\n\r\n /**\r\n * Find passed node's firs-level parent (in example - blockquote)\r\n */\r\n while (current.parentNode && current.parentNode.contentEditable !== 'true') {\r\n current = current.parentNode;\r\n }\r\n\r\n let sibling = direction === 'left' ? 'previousSibling' : 'nextSibling';\r\n\r\n /**\r\n * Find all left/right siblings\r\n */\r\n while (current[sibling]) {\r\n current = current[sibling];\r\n siblings.push(current);\r\n }\r\n\r\n return siblings;\r\n }\r\n\r\n /**\r\n * Set's caret to the next Block\r\n * Before moving caret, we should check if caret position is at the end of Plugins node\r\n * Using {@link Dom#getDeepestNode} to get a last node and match with current selection\r\n *\r\n * @param {Boolean} force - force navigation even if caret is not at the end\r\n *\r\n * @return {Boolean}\r\n */\r\n navigateNext(force = false) {\r\n let nextBlock = this.Editor.BlockManager.nextBlock;\r\n\r\n if (!nextBlock) {\r\n return false;\r\n }\r\n\r\n if (force || this.isAtEnd) {\r\n this.setToBlock(nextBlock);\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Set's caret to the previous Block\r\n * Before moving caret, we should check if caret position is start of the Plugins node\r\n * Using {@link Dom#getDeepestNode} to get a last node and match with current selection\r\n *\r\n * @param {Boolean} force - force navigation even if caret is not at the start\r\n *\r\n * @return {Boolean}\r\n */\r\n navigatePrevious(force = false) {\r\n let previousBlock = this.Editor.BlockManager.previousBlock;\r\n\r\n if (!previousBlock) {\r\n return false;\r\n }\r\n\r\n if (force || this.isAtStart) {\r\n this.setToBlock( previousBlock, 0, true );\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Get's deepest first node and checks if offset is zero\r\n * @return {boolean}\r\n */\r\n get isAtStart() {\r\n /**\r\n * Don't handle ranges\r\n */\r\n if (!Selection.isCollapsed) {\r\n return false;\r\n }\r\n\r\n let selection = Selection.get(),\r\n anchorNode = selection.anchorNode,\r\n firstNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.pluginsContent);\r\n\r\n /**\r\n * Workaround case when caret in the text like \" |Hello!\"\r\n * selection.anchorOffset is 1, but real caret visible position is 0\r\n * @type {number}\r\n */\r\n let firstLetterPosition = anchorNode.textContent.search(/\\S/);\r\n\r\n if (firstLetterPosition === -1) { // empty text\r\n firstLetterPosition = 0;\r\n }\r\n\r\n /**\r\n * In case of\r\n *
    \r\n *

    <-- first (and deepest) node is \r\n * |adaddad <-- anchor node\r\n *
    \r\n */\r\n if ($.isEmpty(firstNode)) {\r\n let leftSiblings = this.getHigherLevelSiblings(anchorNode, 'left'),\r\n nothingAtLeft = leftSiblings.every( node => $.isEmpty(node) );\r\n\r\n\r\n\r\n if (nothingAtLeft && selection.anchorOffset === firstLetterPosition) {\r\n return true;\r\n }\r\n }\r\n\r\n /**\r\n * We use <= comparison for case:\r\n * \"| Hello\" <--- selection.anchorOffset is 0, but firstLetterPosition is 1\r\n */\r\n return firstNode === null || anchorNode === firstNode && selection.anchorOffset <= firstLetterPosition;\r\n }\r\n\r\n /**\r\n * Get's deepest last node and checks if offset is last node text length\r\n * @return {boolean}\r\n */\r\n get isAtEnd() {\r\n /**\r\n * Don't handle ranges\r\n */\r\n if (!Selection.isCollapsed) {\r\n return false;\r\n }\r\n\r\n let selection = Selection.get(),\r\n anchorNode = selection.anchorNode,\r\n lastNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.pluginsContent, true);\r\n\r\n /**\r\n * In case of\r\n *
    \r\n * adaddad| <-- anchor node\r\n *

    <-- first (and deepest) node is \r\n *
    \r\n */\r\n if ($.isEmpty(lastNode)) {\r\n let leftSiblings = this.getHigherLevelSiblings(anchorNode, 'right'),\r\n nothingAtRight = leftSiblings.every( node => $.isEmpty(node) );\r\n\r\n if (nothingAtRight && selection.anchorOffset === anchorNode.textContent.length) {\r\n return true;\r\n }\r\n }\r\n\r\n /**\r\n * Workaround case:\r\n * hello | <--- anchorOffset will be 5, but textContent.length will be 6.\r\n * Why not regular .trim():\r\n * in case of ' hello |' trim() will also remove space at the beginning, so length will be lower than anchorOffset\r\n */\r\n let rightTrimmedText = lastNode.textContent.replace(/\\s+$/, '');\r\n\r\n /**\r\n * We use >= comparison for case:\r\n * \"Hello |\" <--- selection.anchorOffset is 7, but rightTrimmedText is 6\r\n */\r\n return anchorNode === lastNode && selection.anchorOffset >= rightTrimmedText.length;\r\n }\r\n}\r\n","/**\r\n * @module eventDispatcher\r\n *\r\n * Has two important methods:\r\n * - {Function} on - appends subscriber to the event. If event doesn't exist - creates new one\r\n * - {Function} emit - fires all subscribers with data\r\n * - {Function off - unsubsribes callback\r\n *\r\n * @version 1.0.0\r\n *\r\n * @typedef {Events} Events\r\n * @property {Object} subscribers - all subscribers grouped by event name\r\n */\r\nexport default class Events extends Module {\r\n /**\r\n * @constructor\r\n */\r\n constructor({config}) {\r\n super({config});\r\n this.subscribers = {};\r\n }\r\n\r\n /**\r\n * Subscribe any event on callback\r\n *\r\n * @param {String} eventName - event name\r\n * @param {Function} callback - subscriber\r\n */\r\n on(eventName, callback) {\r\n if (!(eventName in this.subscribers)) {\r\n this.subscribers[eventName] = [];\r\n }\r\n\r\n // group by events\r\n this.subscribers[eventName].push(callback);\r\n }\r\n\r\n /**\r\n * Emit callbacks with passed data\r\n *\r\n * @param {String} eventName - event name\r\n * @param {Object} data - subscribers get this data when they were fired\r\n */\r\n emit(eventName, data) {\r\n if (!this.subscribers[eventName]) {\r\n return;\r\n }\r\n\r\n this.subscribers[eventName].reduce(function (previousData, currentHandler) {\r\n let newData = currentHandler(previousData);\r\n\r\n return newData ? newData : previousData;\r\n }, data);\r\n }\r\n\r\n /**\r\n * Unsubsribe callback from event\r\n *\r\n * @param eventName\r\n * @param callback\r\n */\r\n off(eventName, callback) {\r\n for(let i = 0; i < this.subscribers[eventName].length; i++) {\r\n if (this.subscribers[eventName][i] === callback) {\r\n delete this.subscribers[eventName][i];\r\n break;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Destroyer\r\n * clears subsribers list\r\n */\r\n destroy() {\r\n this.subscribers = null;\r\n }\r\n}\r\n","/**\r\n * Codex Editor Listeners module\r\n *\r\n * @module Listeners\r\n *\r\n * Module-decorator for event listeners assignment\r\n *\r\n * @author Codex Team\r\n * @version 2.0.0\r\n */\r\n\r\n/**\r\n * @typedef {Listeners} Listeners\r\n * @property {Array} allListeners\r\n */\r\nexport default class Listeners extends Module {\r\n /**\r\n * @constructor\r\n * @param {EditorConfig} config\r\n */\r\n constructor({config}) {\r\n super({config});\r\n this.allListeners = [];\r\n }\r\n\r\n /**\r\n * Assigns event listener on element\r\n *\r\n * @param {Element} element - DOM element that needs to be listened\r\n * @param {String} eventType - event type\r\n * @param {Function} handler - method that will be fired on event\r\n * @param {Boolean} useCapture - use event bubbling\r\n */\r\n on(element, eventType, handler, useCapture = false) {\r\n let assignedEventData = {\r\n element,\r\n eventType,\r\n handler,\r\n useCapture\r\n };\r\n\r\n let alreadyExist = this.findOne(element, eventType, handler);\r\n\r\n if (alreadyExist) return;\r\n\r\n this.allListeners.push(assignedEventData);\r\n element.addEventListener(eventType, handler, useCapture);\r\n }\r\n\r\n /**\r\n * Removes event listener from element\r\n *\r\n * @param {Element} element - DOM element that we removing listener\r\n * @param {String} eventType - event type\r\n * @param {Function} handler - remove handler, if element listens several handlers on the same event type\r\n * @param {Boolean} useCapture - use event bubbling\r\n */\r\n off(element, eventType, handler, useCapture = false) {\r\n let existingListeners = this.findAll(element, eventType, handler);\r\n\r\n for (let i = 0; i < existingListeners.length; i++) {\r\n let index = this.allListeners.indexOf(existingListeners[i]);\r\n\r\n if (index > 0) {\r\n this.allListeners.splice(index, 1);\r\n }\r\n }\r\n\r\n element.removeEventListener(eventType, handler, useCapture);\r\n }\r\n\r\n /**\r\n * Search method: looks for listener by passed element\r\n * @param {Element} element - searching element\r\n * @returns {Array} listeners that found on element\r\n */\r\n findByElement(element) {\r\n let listenersOnElement = [];\r\n\r\n for (let i = 0; i < this.allListeners.length; i++) {\r\n let listener = this.allListeners[i];\r\n\r\n if (listener.element === element) {\r\n listenersOnElement.push(listener);\r\n }\r\n }\r\n\r\n return listenersOnElement;\r\n }\r\n\r\n /**\r\n * Search method: looks for listener by passed event type\r\n * @param {String} eventType\r\n * @return {Array} listeners that found on element\r\n */\r\n findByType(eventType) {\r\n let listenersWithType = [];\r\n\r\n for (let i = 0; i < this.allListeners.length; i++) {\r\n let listener = this.allListeners[i];\r\n\r\n if (listener.type === eventType) {\r\n listenersWithType.push(listener);\r\n }\r\n }\r\n\r\n return listenersWithType;\r\n }\r\n\r\n /**\r\n * Search method: looks for listener by passed handler\r\n * @param {Function} handler\r\n * @return {Array} listeners that found on element\r\n */\r\n findByHandler(handler) {\r\n let listenersWithHandler = [];\r\n\r\n for (let i = 0; i < this.allListeners.length; i++) {\r\n let listener = this.allListeners[i];\r\n\r\n if (listener.handler === handler) {\r\n listenersWithHandler.push(listener);\r\n }\r\n }\r\n\r\n return listenersWithHandler;\r\n }\r\n\r\n /**\r\n * @param {Element} element\r\n * @param {String} eventType\r\n * @param {Function} handler\r\n * @return {Element|null}\r\n */\r\n findOne(element, eventType, handler) {\r\n let foundListeners = this.findAll(element, eventType, handler);\r\n\r\n return foundListeners.length > 0 ? foundListeners[0] : null;\r\n }\r\n\r\n /**\r\n * @param {Element} element\r\n * @param {String} eventType\r\n * @param {Function} handler\r\n * @return {Array}\r\n */\r\n findAll(element, eventType, handler) {\r\n let found,\r\n foundByElements = element ? this.findByElement(element) : [];\r\n // foundByEventType = eventType ? this.findByType(eventType) : [],\r\n // foundByHandler = handler ? this.findByHandler(handler) : [];\r\n\r\n if (element && eventType && handler) {\r\n found = foundByElements.filter( event => event.eventType === eventType && event.handler === handler );\r\n } else if (element && eventType) {\r\n found = foundByElements.filter( event => event.eventType === eventType);\r\n } else {\r\n found = foundByElements;\r\n }\r\n\r\n return found;\r\n }\r\n\r\n /**\r\n * Removes all listeners\r\n */\r\n removeAll() {\r\n this.allListeners.map( (current) => {\r\n current.element.removeEventListener(current.eventType, current.handler);\r\n });\r\n\r\n this.allListeners = [];\r\n }\r\n}\r\n","/**\r\n * Codex Editor Renderer Module\r\n *\r\n * @module Renderer\r\n * @author CodeX Team\r\n *\r\n * @version 2.0.0\r\n */\r\nexport default class Renderer extends Module {\r\n /**\r\n * @constructor\r\n * @param {EditorConfig} config\r\n */\r\n constructor({config}) {\r\n super({config});\r\n }\r\n\r\n /**\r\n * @typedef {Object} RendererItems\r\n * @property {String} type - tool name\r\n * @property {Object} data - tool data\r\n */\r\n\r\n /**\r\n * @example\r\n *\r\n * items: [\r\n * {\r\n * type : 'paragraph',\r\n * data : {\r\n * text : 'Hello from Codex!'\r\n * }\r\n * },\r\n * {\r\n * type : 'paragraph',\r\n * data : {\r\n * text : 'Leave feedback if you like it!'\r\n * }\r\n * },\r\n * ]\r\n *\r\n */\r\n\r\n /**\r\n * Make plugin blocks from array of plugin`s data\r\n * @param {RendererItems[]} items\r\n */\r\n render(items) {\r\n let chainData = [];\r\n\r\n for (let i = 0; i < items.length; i++) {\r\n chainData.push({\r\n function: () => this.insertBlock(items[i])\r\n });\r\n }\r\n\r\n return _.sequence(chainData);\r\n }\r\n\r\n /**\r\n * Get plugin instance\r\n * Add plugin instance to BlockManager\r\n * Insert block to working zone\r\n *\r\n * @param {Object} item\r\n * @returns {Promise.}\r\n * @private\r\n */\r\n insertBlock(item) {\r\n let tool = item.type,\r\n data = item.data,\r\n settings = item.settings;\r\n\r\n if (tool in this.Editor.Tools.available) {\r\n this.Editor.BlockManager.insert(tool, data, settings);\r\n } else {\r\n /**\r\n * @todo show warning notification message\r\n *\r\n * `${tool} blocks was skipped.`\r\n */\r\n\r\n _.log(`Tool «${tool}» is not found. Check 'tools' property at your initial CodeX Editor config.`, 'warn');\r\n }\r\n\r\n return Promise.resolve();\r\n }\r\n}\r\n","/**\r\n * CodeX Sanitizer\r\n *\r\n * @module Sanitizer\r\n * Clears HTML from taint tags\r\n *\r\n * @version 2.0.0\r\n *\r\n * @example\r\n * Module can be used within two ways:\r\n * 1) When you have an instance\r\n * - this.Editor.Sanitizer.clean(yourTaintString);\r\n * 2) As static method\r\n * - CodexEditor.Sanitizer.clean(yourTaintString, yourCustomConfiguration);\r\n *\r\n * {@link SanitizerConfig}\r\n */\r\n\r\n\r\n/**\r\n * @typedef {Object} SanitizerConfig\r\n * @property {Object} tags - define tags restrictions\r\n *\r\n * @example\r\n *\r\n * tags : {\r\n * p: true,\r\n * a: {\r\n * href: true,\r\n * rel: \"nofollow\",\r\n * target: \"_blank\"\r\n * }\r\n * }\r\n */\r\nexport default class Sanitizer extends Module {\r\n /**\r\n * Initializes Sanitizer module\r\n * Sets default configuration if custom not exists\r\n *\r\n * @property {SanitizerConfig} this.defaultConfig\r\n * @property {HTMLJanitor} this._sanitizerInstance - Sanitizer library\r\n *\r\n * @param {SanitizerConfig} config\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n // default config\r\n this.defaultConfig = null;\r\n this._sanitizerInstance = null;\r\n\r\n /** Custom configuration */\r\n this.sanitizerConfig = config.settings ? config.settings.sanitizer : {};\r\n\r\n /** HTML Janitor library */\r\n this.sanitizerInstance = require('html-janitor');\r\n }\r\n\r\n /**\r\n * If developer uses editor's API, then he can customize sanitize restrictions.\r\n * Or, sanitizing config can be defined globally in editors initialization. That config will be used everywhere\r\n * At least, if there is no config overrides, that API uses Default configuration\r\n *\r\n * @uses https://www.npmjs.com/package/html-janitor\r\n *\r\n * @param {HTMLJanitor} library - sanitizer extension\r\n */\r\n set sanitizerInstance(library) {\r\n this._sanitizerInstance = new library(this.defaultConfig);\r\n }\r\n\r\n /**\r\n * Sets sanitizer configuration. Uses default config if user didn't pass the restriction\r\n * @param {SanitizerConfig} config\r\n */\r\n set sanitizerConfig(config) {\r\n if (_.isEmpty(config)) {\r\n this.defaultConfig = {\r\n tags: {\r\n p: {},\r\n a: {\r\n href: true,\r\n target: '_blank',\r\n rel: 'nofollow'\r\n }\r\n }\r\n };\r\n } else {\r\n this.defaultConfig = config;\r\n }\r\n }\r\n\r\n /**\r\n * Cleans string from unwanted tags\r\n * @param {String} taintString - HTML string\r\n * @param {Object} customConfig - custom sanitizer configuration. Method uses default if param is empty\r\n * @return {String} clean HTML\r\n */\r\n clean(taintString, customConfig = {}) {\r\n if (_.isEmpty(customConfig)) {\r\n return this._sanitizerInstance.clean(taintString);\r\n } else {\r\n return Sanitizer.clean(taintString, customConfig);\r\n }\r\n }\r\n\r\n /**\r\n * Cleans string from unwanted tags\r\n * @static\r\n *\r\n * Method allows to use default config\r\n *\r\n * @param {String} taintString - taint string\r\n * @param {SanitizerConfig} customConfig - allowed tags\r\n *\r\n * @return {String} clean HTML\r\n */\r\n static clean(taintString, customConfig) {\r\n let newInstance = Sanitizer(customConfig);\r\n\r\n return newInstance.clean(taintString);\r\n }\r\n}\r\n","/**\r\n * Codex Editor Saver\r\n *\r\n * @module Saver\r\n * @author Codex Team\r\n * @version 2.0.0\r\n */\r\n\r\n/**\r\n * @typedef {Object} SavedData\r\n * @property {Date} time - saving proccess time\r\n * @property {Object} items - extracted data\r\n * @property {String} version - CodexEditor version\r\n */\r\n\r\n/**\r\n * @classdesc This method reduces all Blocks asyncronically and calls Block's save method to extract data\r\n *\r\n * @typedef {Saver} Saver\r\n * @property {Element} html - Editor HTML content\r\n * @property {String} json - Editor JSON output\r\n */\r\nexport default class Saver extends Module {\r\n /**\r\n * @constructor\r\n * @param config\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n this.output = null;\r\n this.blocksData = [];\r\n }\r\n\r\n /**\r\n * Composes new chain of Promises to fire them alternatelly\r\n * @return {SavedData}\r\n */\r\n save() {\r\n let blocks = this.Editor.BlockManager.blocks,\r\n chainData = [];\r\n\r\n blocks.forEach((block) => {\r\n chainData.push(block.data);\r\n });\r\n\r\n return Promise.all(chainData)\r\n .then((allExtractedData) => this.makeOutput(allExtractedData))\r\n .then((outputData) => {\r\n return outputData;\r\n });\r\n }\r\n\r\n /**\r\n * Creates output object with saved data, time and version of editor\r\n * @param {Object} allExtractedData\r\n * @return {SavedData}\r\n */\r\n makeOutput(allExtractedData) {\r\n let items = [],\r\n totalTime = 0;\r\n\r\n console.groupCollapsed('[CodexEditor saving]:');\r\n\r\n allExtractedData.forEach((extraction) => {\r\n /** Group process info */\r\n console.log(`«${extraction.tool}» saving info`, extraction);\r\n totalTime += extraction.time;\r\n items.push({\r\n type: extraction.tool,\r\n data: extraction.data\r\n });\r\n });\r\n\r\n console.log('Total', totalTime);\r\n console.groupEnd();\r\n\r\n return {\r\n time : +new Date(),\r\n items : items,\r\n version : VERSION,\r\n };\r\n }\r\n}\r\n\r\n// module.exports = (function (saver) {\r\n//\r\n// let editor = codex.editor;\r\n//\r\n// /**\r\n// * @public\r\n// * Save blocks\r\n// */\r\n// saver.save = function () {\r\n//\r\n// /** Save html content of redactor to memory */\r\n// editor.state.html = editor.nodes.redactor.innerHTML;\r\n//\r\n// /** Clean jsonOutput state */\r\n// editor.state.jsonOutput = [];\r\n//\r\n// return saveBlocks(editor.nodes.redactor.childNodes);\r\n//\r\n// };\r\n//\r\n// /**\r\n// * @private\r\n// * Save each block data\r\n// *\r\n// * @param blocks\r\n// * @returns {Promise.}\r\n// */\r\n// let saveBlocks = function (blocks) {\r\n//\r\n// let data = [];\r\n//\r\n// for(let index = 0; index < blocks.length; index++) {\r\n//\r\n// data.push(getBlockData(blocks[index]));\r\n//\r\n// }\r\n//\r\n// return Promise.all(data)\r\n// .then(makeOutput)\r\n// .catch(editor.core.log);\r\n//\r\n// };\r\n//\r\n// /** Save and validate block data */\r\n// let getBlockData = function (block) {\r\n//\r\n// return saveBlockData(block)\r\n// .then(validateBlockData)\r\n// .catch(editor.core.log);\r\n//\r\n// };\r\n//\r\n// /**\r\n// * @private\r\n// * Call block`s plugin save method and return saved data\r\n// *\r\n// * @param block\r\n// * @returns {Object}\r\n// */\r\n// let saveBlockData = function (block) {\r\n//\r\n// let pluginName = block.dataset.tool;\r\n//\r\n// /** Check for plugin existence */\r\n// if (!editor.tools[pluginName]) {\r\n//\r\n// editor.core.log(`Plugin «${pluginName}» not found`, 'error');\r\n// return {data: null, pluginName: null};\r\n//\r\n// }\r\n//\r\n// /** Check for plugin having save method */\r\n// if (typeof editor.tools[pluginName].save !== 'function') {\r\n//\r\n// editor.core.log(`Plugin «${pluginName}» must have save method`, 'error');\r\n// return {data: null, pluginName: null};\r\n//\r\n// }\r\n//\r\n// /** Result saver */\r\n// let blockContent = block.childNodes[0],\r\n// pluginsContent = blockContent.childNodes[0],\r\n// position = pluginsContent.dataset.inputPosition;\r\n//\r\n// /** If plugin wasn't available then return data from cache */\r\n// if ( editor.tools[pluginName].available === false ) {\r\n//\r\n// return Promise.resolve({data: codex.editor.state.blocks.items[position].data, pluginName});\r\n//\r\n// }\r\n//\r\n// return Promise.resolve(pluginsContent)\r\n// .then(editor.tools[pluginName].save)\r\n// .then(data => Object({data, pluginName}));\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Call plugin`s validate method. Return false if validation failed\r\n// *\r\n// * @param data\r\n// * @param pluginName\r\n// * @returns {Object|Boolean}\r\n// */\r\n// let validateBlockData = function ({data, pluginName}) {\r\n//\r\n// if (!data || !pluginName) {\r\n//\r\n// return false;\r\n//\r\n// }\r\n//\r\n// if (editor.tools[pluginName].validate) {\r\n//\r\n// let result = editor.tools[pluginName].validate(data);\r\n//\r\n// /**\r\n// * Do not allow invalid data\r\n// */\r\n// if (!result) {\r\n//\r\n// return false;\r\n//\r\n// }\r\n//\r\n// }\r\n//\r\n// return {data, pluginName};\r\n//\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Compile article output\r\n// *\r\n// * @param savedData\r\n// * @returns {{time: number, version, items: (*|Array)}}\r\n// */\r\n// let makeOutput = function (savedData) {\r\n//\r\n// savedData = savedData.filter(blockData => blockData);\r\n//\r\n// let items = savedData.map(blockData => Object({type: blockData.pluginName, data: blockData.data}));\r\n//\r\n// editor.state.jsonOutput = items;\r\n//\r\n// return {\r\n// id: editor.state.blocks.id || null,\r\n// time: +new Date(),\r\n// version: editor.version,\r\n// items\r\n// };\r\n//\r\n// };\r\n//\r\n// return saver;\r\n//\r\n// })({});\r\n","/**\r\n * Block Settings\r\n *\r\n * ____ Settings Panel ____\r\n * | ...................... |\r\n * | . Tool Settings . |\r\n * | ...................... |\r\n * | . Default Settings . |\r\n * | ...................... |\r\n * |________________________|\r\n */\r\nexport default class BlockSettings extends Module {\r\n /**\r\n * @constructor\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n this.nodes = {\r\n wrapper: null,\r\n toolSettings: null,\r\n defaultSettings: null\r\n };\r\n }\r\n\r\n /**\r\n * Module Events\r\n * @return {{opened: string, closed: string}}\r\n */\r\n get events() {\r\n return {\r\n opened: 'block-settings-opened',\r\n closed: 'block-settings-closed',\r\n };\r\n }\r\n\r\n /**\r\n * Block Settings CSS\r\n * @return {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}}\r\n */\r\n static get CSS() {\r\n return {\r\n // Settings Panel\r\n wrapper: 'ce-settings',\r\n wrapperOpened: 'ce-settings--opened',\r\n toolSettings: 'ce-settings__plugin-zone',\r\n defaultSettings: 'ce-settings__default-zone',\r\n\r\n button: 'ce-settings__button'\r\n };\r\n }\r\n\r\n /**\r\n * Panel with block settings with 2 sections:\r\n * - Tool's Settings\r\n * - Default Settings [Move, Remove, etc]\r\n *\r\n * @return {Element}\r\n */\r\n make() {\r\n this.nodes.wrapper = $.make('div', BlockSettings.CSS.wrapper);\r\n\r\n this.nodes.toolSettings = $.make('div', BlockSettings.CSS.toolSettings);\r\n this.nodes.defaultSettings = $.make('div', BlockSettings.CSS.defaultSettings);\r\n\r\n $.append(this.nodes.wrapper, [this.nodes.toolSettings, this.nodes.defaultSettings]);\r\n }\r\n\r\n /**\r\n * Add Tool's settings\r\n */\r\n addToolSettings() {\r\n if (typeof this.Editor.BlockManager.currentBlock.tool.makeSettings === 'function') {\r\n $.append(this.nodes.toolSettings, this.Editor.BlockManager.currentBlock.tool.makeSettings());\r\n }\r\n }\r\n\r\n /**\r\n * Add default settings\r\n */\r\n addDefaultSettings() {\r\n $.append(this.nodes.defaultSettings, this.Editor.BlockManager.currentBlock.renderTunes());\r\n }\r\n\r\n /**\r\n * Is Block Settings opened or not\r\n * @returns {boolean}\r\n */\r\n get opened() {\r\n return this.nodes.wrapper.classList.contains(BlockSettings.CSS.wrapperOpened);\r\n }\r\n\r\n /**\r\n * Open Block Settings pane\r\n */\r\n open() {\r\n this.nodes.wrapper.classList.add(BlockSettings.CSS.wrapperOpened);\r\n\r\n /**\r\n * Fill Tool's settings\r\n */\r\n this.addToolSettings();\r\n\r\n /**\r\n * Add default settings that presents for all Blocks\r\n */\r\n this.addDefaultSettings();\r\n\r\n /** Tell to subscribers that block settings is opened */\r\n this.Editor.Events.emit(this.events.opened);\r\n }\r\n\r\n /**\r\n * Close Block Settings pane\r\n */\r\n close() {\r\n this.nodes.wrapper.classList.remove(BlockSettings.CSS.wrapperOpened);\r\n\r\n /** Clear settings */\r\n this.nodes.toolSettings.innerHTML = '';\r\n this.nodes.defaultSettings.innerHTML = '';\r\n\r\n /** Tell to subscribers that block settings is closed */\r\n this.Editor.Events.emit(this.events.closed);\r\n }\r\n}\r\n","import BoldInlineTool from '../inline-tools/inline-tool-bold';\r\nimport ItalicInlineTool from '../inline-tools/inline-tool-italic';\r\nimport LinkInlineTool from '../inline-tools/inline-tool-link';\r\nimport Selection from '../selection';\r\nexport default class InlineToolbar extends Module {\r\n /**\r\n * @constructor\r\n */\r\n constructor({ config }) {\r\n super({ config });\r\n /**\r\n * CSS styles\r\n */\r\n this.CSS = {\r\n inlineToolbar: 'ce-inline-toolbar',\r\n inlineToolbarShowed: 'ce-inline-toolbar--showed',\r\n buttonsWrapper: 'ce-inline-toolbar__buttons',\r\n actionsWrapper: 'ce-inline-toolbar__actions',\r\n };\r\n /**\r\n * Inline Toolbar elements\r\n */\r\n this.nodes = {\r\n wrapper: null,\r\n buttons: null,\r\n /**\r\n * Zone below the buttons where Tools can create additional actions by 'renderActions()' method\r\n * For example, input for the 'link' tool or textarea for the 'comment' tool\r\n */\r\n actions: null,\r\n };\r\n /**\r\n * Margin above/below the Toolbar\r\n */\r\n this.toolbarVerticalMargin = 20;\r\n }\r\n /**\r\n * Inline Toolbar Tools\r\n * @todo Merge internal tools with external\r\n */\r\n get tools() {\r\n if (!this.toolsInstances) {\r\n this.toolsInstances = [\r\n new BoldInlineTool(this.Editor.API.methods),\r\n new ItalicInlineTool(this.Editor.API.methods),\r\n new LinkInlineTool(this.Editor.API.methods),\r\n ...this.Editor.Tools.inline.map((Tool) => new Tool(this.Editor.API.methods)),\r\n ];\r\n }\r\n return this.toolsInstances;\r\n }\r\n /**\r\n * Making DOM\r\n */\r\n make() {\r\n this.nodes.wrapper = $.make('div', this.CSS.inlineToolbar);\r\n this.nodes.buttons = $.make('div', this.CSS.buttonsWrapper);\r\n this.nodes.actions = $.make('div', this.CSS.actionsWrapper);\r\n /**\r\n * Append Inline Toolbar to the Editor\r\n */\r\n $.append(this.nodes.wrapper, [this.nodes.buttons, this.nodes.actions]);\r\n $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);\r\n /**\r\n * Append Inline Toolbar Tools\r\n */\r\n this.addTools();\r\n }\r\n /**\r\n *\r\n *\r\n * Moving / appearance\r\n * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n *\r\n */\r\n /**\r\n * Shows Inline Toolbar by keyup/mouseup\r\n * @param {KeyboardEvent|MouseEvent} event\r\n */\r\n handleShowingEvent(event) {\r\n if (!this.allowedToShow(event)) {\r\n this.close();\r\n return;\r\n }\r\n this.move();\r\n this.open();\r\n /** Check Tools state for selected fragment */\r\n this.checkToolsState();\r\n }\r\n /**\r\n * Move Toolbar to the selected text\r\n */\r\n move() {\r\n const selectionRect = Selection.rect;\r\n const wrapperOffset = this.Editor.UI.nodes.wrapper.getBoundingClientRect();\r\n const newCoords = {\r\n x: selectionRect.x - wrapperOffset.left,\r\n y: selectionRect.y\r\n + selectionRect.height\r\n // + window.scrollY\r\n - wrapperOffset.top\r\n + this.toolbarVerticalMargin,\r\n };\r\n /**\r\n * If we know selections width, place InlineToolbar to center\r\n */\r\n if (selectionRect.width) {\r\n newCoords.x += Math.floor(selectionRect.width / 2);\r\n }\r\n this.nodes.wrapper.style.left = Math.floor(newCoords.x) + 'px';\r\n this.nodes.wrapper.style.top = Math.floor(newCoords.y) + 'px';\r\n }\r\n /**\r\n * Shows Inline Toolbar\r\n */\r\n open() {\r\n this.nodes.wrapper.classList.add(this.CSS.inlineToolbarShowed);\r\n this.tools.forEach((tool) => {\r\n if (typeof tool.clear === 'function') {\r\n tool.clear();\r\n }\r\n });\r\n }\r\n /**\r\n * Hides Inline Toolbar\r\n */\r\n close() {\r\n this.nodes.wrapper.classList.remove(this.CSS.inlineToolbarShowed);\r\n this.tools.forEach((tool) => {\r\n if (typeof tool.clear === 'function') {\r\n tool.clear();\r\n }\r\n });\r\n }\r\n /**\r\n * Need to show Inline Toolbar or not\r\n * @param {KeyboardEvent|MouseEvent} event\r\n */\r\n allowedToShow(event) {\r\n /**\r\n * Tags conflicts with window.selection function.\r\n * Ex. IMG tag returns null (Firefox) or Redactors wrapper (Chrome)\r\n */\r\n const tagsConflictsWithSelection = ['IMG', 'INPUT'];\r\n if (event && tagsConflictsWithSelection.includes(event.target.tagName)) {\r\n return false;\r\n }\r\n const currentSelection = Selection.get(), selectedText = Selection.text;\r\n // old browsers\r\n if (!currentSelection || !currentSelection.anchorNode) {\r\n return false;\r\n }\r\n // empty selection\r\n if (currentSelection.isCollapsed || selectedText.length < 1) {\r\n return false;\r\n }\r\n // is enabled by current Block's Tool\r\n const currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode);\r\n if (!currentBlock) {\r\n return false;\r\n }\r\n const toolConfig = this.config.toolsConfig[currentBlock.name];\r\n return toolConfig && toolConfig[this.Editor.Tools.apiSettings.IS_ENABLED_INLINE_TOOLBAR];\r\n }\r\n /**\r\n *\r\n *\r\n * Working with Tools\r\n * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n *\r\n */\r\n /**\r\n * Fill Inline Toolbar with Tools\r\n */\r\n addTools() {\r\n this.tools.forEach((tool) => {\r\n this.addTool(tool);\r\n });\r\n }\r\n /**\r\n * Add tool button and activate clicks\r\n * @param {InlineTool} tool - Tool's instance\r\n */\r\n addTool(tool) {\r\n const button = tool.render();\r\n if (!button) {\r\n _.log('Render method must return an instance of Node', 'warn', tool);\r\n return;\r\n }\r\n this.nodes.buttons.appendChild(button);\r\n if (typeof tool.renderActions === 'function') {\r\n const actions = tool.renderActions();\r\n this.nodes.actions.appendChild(actions);\r\n }\r\n this.Editor.Listeners.on(button, 'click', () => {\r\n this.toolClicked(tool);\r\n });\r\n }\r\n /**\r\n * Inline Tool button clicks\r\n * @param {InlineTool} tool - Tool's instance\r\n */\r\n toolClicked(tool) {\r\n const range = Selection.range;\r\n tool.surround(range);\r\n this.checkToolsState();\r\n }\r\n /**\r\n * Check Tools` state by selection\r\n */\r\n checkToolsState() {\r\n this.tools.forEach((tool) => {\r\n tool.checkState(Selection.get());\r\n });\r\n }\r\n}\r\n","/**\r\n * @class Toolbox\r\n * @classdesc Holder for Tools\r\n *\r\n * @typedef {Toolbox} Toolbox\r\n * @property {Boolean} opened - opening state\r\n * @property {Object} nodes - Toolbox nodes\r\n * @property {Object} CSS - CSS class names\r\n *\r\n */\r\nexport default class Toolbox extends Module {\r\n /**\r\n * @constructor\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n this.nodes = {\r\n toolbox: null,\r\n buttons: []\r\n };\r\n\r\n /**\r\n * Opening state\r\n * @type {boolean}\r\n */\r\n this.opened = false;\r\n }\r\n\r\n /**\r\n * CSS styles\r\n * @return {{toolbox: string, toolboxButton: string, toolboxOpened: string}}\r\n */\r\n static get CSS() {\r\n return {\r\n toolbox: 'ce-toolbox',\r\n toolboxButton: 'ce-toolbox__button',\r\n toolboxOpened: 'ce-toolbox--opened',\r\n };\r\n }\r\n\r\n /**\r\n * Makes the Toolbox\r\n */\r\n make() {\r\n this.nodes.toolbox = $.make('div', Toolbox.CSS.toolbox);\r\n $.append(this.Editor.Toolbar.nodes.content, this.nodes.toolbox);\r\n\r\n this.addTools();\r\n }\r\n\r\n /**\r\n * Iterates available tools and appends them to the Toolbox\r\n */\r\n addTools() {\r\n let tools = this.Editor.Tools.toolsAvailable;\r\n\r\n for (let toolName in tools) {\r\n this.addTool(toolName, tools[toolName]);\r\n }\r\n }\r\n\r\n /**\r\n * Append Tool to the Toolbox\r\n *\r\n * @param {string} toolName - tool name\r\n * @param {Tool} tool - tool class\r\n */\r\n addTool(toolName, tool) {\r\n const api = this.Editor.Tools.apiSettings;\r\n\r\n if (tool[api.IS_DISPLAYED_IN_TOOLBOX] && !tool[api.TOOLBAR_ICON_CLASS]) {\r\n _.log('Toolbar icon class name is missed. Tool %o skipped', 'warn', toolName);\r\n return;\r\n }\r\n\r\n /**\r\n * @todo Add checkup for the render method\r\n */\r\n // if (typeof tool.render !== 'function') {\r\n //\r\n // _.log('render method missed. Tool %o skipped', 'warn', tool);\r\n // return;\r\n //\r\n // }\r\n\r\n /**\r\n * Skip tools that pass 'displayInToolbox=false'\r\n */\r\n if (!tool[api.IS_DISPLAYED_IN_TOOLBOX]) {\r\n return;\r\n }\r\n\r\n let button = $.make('li', [Toolbox.CSS.toolboxButton, tool[api.TOOLBAR_ICON_CLASS]], {\r\n title: toolName\r\n });\r\n\r\n /**\r\n * Save tool's name in the button data-name\r\n */\r\n button.dataset.name = toolName;\r\n\r\n $.append(this.nodes.toolbox, button);\r\n\r\n this.nodes.toolbox.appendChild(button);\r\n this.nodes.buttons.push(button);\r\n\r\n /**\r\n * @todo add event with module Listeners\r\n */\r\n // this.Editor.Listeners.add();\r\n button.addEventListener('click', event => {\r\n this.buttonClicked(event);\r\n }, false);\r\n }\r\n\r\n /**\r\n * Toolbox button click listener\r\n * 1) if block is empty -> replace\r\n * 2) if block is not empty -> add new block below\r\n *\r\n * @param {MouseEvent} event\r\n */\r\n buttonClicked(event) {\r\n let toolButton = event.target,\r\n toolName = toolButton.dataset.name,\r\n tool = this.Editor.Tools.toolClasses[toolName];\r\n\r\n /**\r\n * @type {Block}\r\n */\r\n let currentBlock = this.Editor.BlockManager.currentBlock;\r\n\r\n /**\r\n * We do replace if:\r\n * - block is empty\r\n * - block is not irreplaceable\r\n * @type {Array}\r\n */\r\n if (!tool[this.Editor.Tools.apiSettings.IS_IRREPLACEBLE_TOOL] && currentBlock.isEmpty) {\r\n this.Editor.BlockManager.replace(toolName);\r\n } else {\r\n this.Editor.BlockManager.insert(toolName);\r\n }\r\n\r\n /**\r\n * @todo set caret to the new block\r\n */\r\n\r\n // window.setTimeout(function () {\r\n\r\n /** Set caret to current block */\r\n // editor.caret.setToBlock(currentInputIndex);\r\n\r\n // }, 10);\r\n\r\n /**\r\n * Move toolbar when node is changed\r\n */\r\n this.Editor.Toolbar.move();\r\n }\r\n\r\n /**\r\n * Open Toolbox with Tools\r\n */\r\n open() {\r\n this.nodes.toolbox.classList.add(Toolbox.CSS.toolboxOpened);\r\n this.opened = true;\r\n }\r\n\r\n /**\r\n * Close Toolbox\r\n */\r\n close() {\r\n this.nodes.toolbox.classList.remove(Toolbox.CSS.toolboxOpened);\r\n this.opened = false;\r\n }\r\n\r\n /**\r\n * Close Toolbox\r\n */\r\n toggle() {\r\n if (!this.opened) {\r\n this.open();\r\n } else {\r\n this.close();\r\n }\r\n }\r\n}\r\n","/**\r\n *\r\n * «Toolbar» is the node that moves up/down over current block\r\n *\r\n * ______________________________________ Toolbar ____________________________________________\r\n * | |\r\n * | ..................... Content .................... ......... Block Actions .......... |\r\n * | . . . . |\r\n * | . . . [Open Settings] . |\r\n * | . [Plus Button] [Toolbox: {Tool1}, {Tool2}] . . . |\r\n * | . . . [Settings Panel] . |\r\n * | .................................................. .................................. |\r\n * | |\r\n * |___________________________________________________________________________________________|\r\n *\r\n *\r\n * Toolbox — its an Element contains tools buttons. Can be shown by Plus Button.\r\n *\r\n * _______________ Toolbox _______________\r\n * | |\r\n * | [Header] [Image] [List] [Quote] ... |\r\n * |_______________________________________|\r\n *\r\n *\r\n * Settings Panel — is an Element with block settings:\r\n *\r\n * ____ Settings Panel ____\r\n * | ...................... |\r\n * | . Tool Settings . |\r\n * | ...................... |\r\n * | . Default Settings . |\r\n * | ...................... |\r\n * |________________________|\r\n *\r\n *\r\n * @class\r\n * @classdesc Toolbar module\r\n *\r\n * @typedef {Toolbar} Toolbar\r\n * @property {Object} nodes\r\n * @property {Element} nodes.wrapper - Toolbar main element\r\n * @property {Element} nodes.content - Zone with Plus button and toolbox.\r\n * @property {Element} nodes.actions - Zone with Block Settings and Remove Button\r\n * @property {Element} nodes.blockActionsButtons - Zone with Block Buttons: [Settings]\r\n * @property {Element} nodes.plusButton - Button that opens or closes Toolbox\r\n * @property {Element} nodes.toolbox - Container for tools\r\n * @property {Element} nodes.settingsToggler - open/close Settings Panel button\r\n * @property {Element} nodes.settings - Settings Panel\r\n * @property {Element} nodes.pluginSettings - Plugin Settings section of Settings Panel\r\n * @property {Element} nodes.defaultSettings - Default Settings section of Settings Panel\r\n */\r\nexport default class Toolbar extends Module {\r\n /**\r\n * @constructor\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n this.nodes = {\r\n wrapper : null,\r\n content : null,\r\n actions : null,\r\n\r\n // Content Zone\r\n plusButton : null,\r\n\r\n // Actions Zone\r\n blockActionsButtons: null,\r\n settingsToggler : null,\r\n };\r\n }\r\n\r\n /**\r\n * CSS styles\r\n * @return {Object}\r\n * @constructor\r\n */\r\n static get CSS() {\r\n return {\r\n toolbar: 'ce-toolbar',\r\n content: 'ce-toolbar__content',\r\n actions: 'ce-toolbar__actions',\r\n\r\n toolbarOpened: 'ce-toolbar--opened',\r\n\r\n // Content Zone\r\n plusButton: 'ce-toolbar__plus',\r\n plusButtonHidden: 'ce-toolbar__plus--hidden',\r\n\r\n // Actions Zone\r\n blockActionsButtons: 'ce-toolbar__actions-buttons',\r\n settingsToggler: 'ce-toolbar__settings-btn',\r\n };\r\n }\r\n\r\n /**\r\n * Makes toolbar\r\n */\r\n make() {\r\n this.nodes.wrapper = $.make('div', Toolbar.CSS.toolbar);\r\n\r\n /**\r\n * Make Content Zone and Actions Zone\r\n */\r\n ['content', 'actions'].forEach( el => {\r\n this.nodes[el] = $.make('div', Toolbar.CSS[el]);\r\n $.append(this.nodes.wrapper, this.nodes[el]);\r\n });\r\n\r\n\r\n /**\r\n * Fill Content Zone:\r\n * - Plus Button\r\n * - Toolbox\r\n */\r\n this.nodes.plusButton = $.make('div', Toolbar.CSS.plusButton);\r\n $.append(this.nodes.plusButton, $.svg('plus', 14, 14));\r\n $.append(this.nodes.content, this.nodes.plusButton);\r\n this.nodes.plusButton.addEventListener('click', event => this.plusButtonClicked(event), false);\r\n\r\n\r\n /**\r\n * Make a Toolbox\r\n */\r\n this.Editor.Toolbox.make();\r\n\r\n /**\r\n * Fill Actions Zone:\r\n * - Settings Toggler\r\n * - Remove Block Button\r\n * - Settings Panel\r\n */\r\n this.nodes.blockActionsButtons = $.make('div', Toolbar.CSS.blockActionsButtons);\r\n this.nodes.settingsToggler = $.make('span', Toolbar.CSS.settingsToggler);\r\n const settingsIcon = $.svg('dots', 18, 4);\r\n\r\n $.append(this.nodes.settingsToggler, settingsIcon);\r\n $.append(this.nodes.blockActionsButtons, this.nodes.settingsToggler);\r\n $.append(this.nodes.actions, this.nodes.blockActionsButtons);\r\n\r\n /**\r\n * Make and append Settings Panel\r\n */\r\n this.Editor.BlockSettings.make();\r\n $.append(this.nodes.actions, this.Editor.BlockSettings.nodes.wrapper);\r\n\r\n /**\r\n * Append toolbar to the Editor\r\n */\r\n $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);\r\n\r\n /**\r\n * Bind events on the Toolbar elements\r\n */\r\n this.bindEvents();\r\n }\r\n\r\n /**\r\n * Move Toolbar to the Current Block\r\n * @param {Boolean} forceClose - force close Toolbar Settings and Toolbar\r\n */\r\n move(forceClose = true) {\r\n if (forceClose) {\r\n /** Close Toolbox when we move toolbar */\r\n this.Editor.Toolbox.close();\r\n this.Editor.BlockSettings.close();\r\n }\r\n\r\n let currentNode = this.Editor.BlockManager.currentNode;\r\n\r\n /**\r\n * If no one Block selected as a Current\r\n */\r\n if (!currentNode) {\r\n return;\r\n }\r\n\r\n /**\r\n * @todo Compute dynamically on prepare\r\n * @type {number}\r\n */\r\n const defaultToolbarHeight = 49;\r\n const defaultOffset = 34;\r\n\r\n var newYCoordinate = currentNode.offsetTop - (defaultToolbarHeight / 2) + defaultOffset;\r\n\r\n this.nodes.wrapper.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;\r\n }\r\n\r\n /**\r\n * Open Toolbar with Plus Button\r\n */\r\n open() {\r\n this.nodes.wrapper.classList.add(Toolbar.CSS.toolbarOpened);\r\n }\r\n\r\n /**\r\n * Close the Toolbar\r\n */\r\n close() {\r\n this.nodes.wrapper.classList.remove(Toolbar.CSS.toolbarOpened);\r\n }\r\n\r\n /**\r\n * Plus Button public methods\r\n * @return {{hide: function(): void, show: function(): void}}\r\n */\r\n get plusButton() {\r\n return {\r\n hide: () => this.nodes.plusButton.classList.add(Toolbar.CSS.plusButtonHidden),\r\n show: () => this.nodes.plusButton.classList.remove(Toolbar.CSS.plusButtonHidden)\r\n };\r\n }\r\n\r\n /**\r\n * Handler for Plus Button\r\n * @param {MouseEvent} event\r\n */\r\n plusButtonClicked() {\r\n this.Editor.Toolbox.toggle();\r\n }\r\n\r\n /**\r\n * Bind events on the Toolbar Elements:\r\n * - Block Settings\r\n */\r\n bindEvents() {\r\n /**\r\n * Settings toggler\r\n */\r\n this.Editor.Listeners.on(this.nodes.settingsToggler, 'click', (event) => {\r\n this.settingsTogglerClicked(event);\r\n });\r\n }\r\n\r\n /**\r\n * Clicks on the Block Settings toggler\r\n */\r\n settingsTogglerClicked() {\r\n if (this.Editor.BlockSettings.opened) {\r\n this.Editor.BlockSettings.close();\r\n } else {\r\n this.Editor.BlockSettings.open();\r\n }\r\n }\r\n}\r\n","/**\r\n * Inline toolbar\r\n *\r\n * Contains from tools:\r\n * Bold, Italic, Underline and Anchor\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = (function (inline) {\n let editor = codex.editor;\r\n\r\n inline.buttonsOpened = null;\r\n inline.actionsOpened = null;\r\n inline.wrappersOffset = null;\r\n\r\n /**\r\n * saving selection that need for execCommand for styling\r\n *\r\n */\r\n inline.storedSelection = null;\r\n\r\n /**\r\n * @protected\r\n *\r\n * Open inline toobar\r\n */\r\n inline.show = function () {\n var currentNode = editor.content.currentNode,\r\n tool = currentNode.dataset.tool,\r\n plugin;\r\n\r\n /**\r\n * tool allowed to open inline toolbar\r\n */\r\n plugin = editor.tools[tool];\r\n\r\n if (!plugin.showInlineToolbar)\r\n return;\r\n\r\n var selectedText = inline.getSelectionText(),\r\n toolbar = editor.nodes.inlineToolbar.wrapper;\r\n\r\n if (selectedText.length > 0) {\n /** Move toolbar and open */\r\n editor.toolbar.inline.move();\r\n\r\n /** Open inline toolbar */\r\n toolbar.classList.add('opened');\r\n\r\n /** show buttons of inline toolbar */\r\n editor.toolbar.inline.showButtons();\n }\n };\r\n\r\n /**\r\n * @protected\r\n *\r\n * Closes inline toolbar\r\n */\r\n inline.close = function () {\n var toolbar = editor.nodes.inlineToolbar.wrapper;\r\n\r\n toolbar.classList.remove('opened');\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Moving toolbar\r\n */\r\n inline.move = function () {\n if (!this.wrappersOffset) {\n this.wrappersOffset = this.getWrappersOffset();\n }\r\n\r\n var coords = this.getSelectionCoords(),\r\n defaultOffset = 0,\r\n toolbar = editor.nodes.inlineToolbar.wrapper,\r\n newCoordinateX,\r\n newCoordinateY;\r\n\r\n if (toolbar.offsetHeight === 0) {\n defaultOffset = 40;\n }\r\n\r\n newCoordinateX = coords.x - this.wrappersOffset.left;\r\n newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;\r\n\r\n toolbar.style.transform = `translate3D(${Math.floor(newCoordinateX)}px, ${Math.floor(newCoordinateY)}px, 0)`;\r\n\r\n /** Close everything */\r\n editor.toolbar.inline.closeButtons();\r\n editor.toolbar.inline.closeAction();\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Tool Clicked\r\n */\r\n\r\n inline.toolClicked = function (event, type) {\n /**\r\n * For simple tools we use default browser function\r\n * For more complicated tools, we should write our own behavior\r\n */\r\n switch (type) {\n case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break;\r\n default : editor.toolbar.inline.defaultToolAction(type); break;\n }\r\n\r\n /**\r\n * highlight buttons\r\n * after making some action\r\n */\r\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Saving wrappers offset in DOM\r\n */\r\n inline.getWrappersOffset = function () {\n var wrapper = editor.nodes.wrapper,\r\n offset = this.getOffset(wrapper);\r\n\r\n this.wrappersOffset = offset;\r\n return offset;\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Calculates offset of DOM element\r\n *\r\n * @param el\r\n * @returns {{top: number, left: number}}\r\n */\r\n inline.getOffset = function ( el ) {\n var _x = 0;\r\n var _y = 0;\r\n\r\n while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {\n _x += (el.offsetLeft + el.clientLeft);\r\n _y += (el.offsetTop + el.clientTop);\r\n el = el.offsetParent;\n }\r\n return { top: _y, left: _x };\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Calculates position of selected text\r\n * @returns {{x: number, y: number}}\r\n */\r\n inline.getSelectionCoords = function () {\n var sel = document.selection, range;\r\n var x = 0, y = 0;\r\n\r\n if (sel) {\n if (sel.type != 'Control') {\n range = sel.createRange();\r\n range.collapse(true);\r\n x = range.boundingLeft;\r\n y = range.boundingTop;\n }\n } else if (window.getSelection) {\n sel = window.getSelection();\r\n\r\n if (sel.rangeCount) {\n range = sel.getRangeAt(0).cloneRange();\r\n if (range.getClientRects) {\n range.collapse(true);\r\n var rect = range.getClientRects()[0];\r\n\r\n if (!rect) {\n return;\n }\r\n\r\n x = rect.left;\r\n y = rect.top;\n }\n }\n }\r\n return { x: x, y: y };\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Returns selected text as String\r\n * @returns {string}\r\n */\r\n inline.getSelectionText = function () {\n var selectedText = '';\r\n\r\n // all modern browsers and IE9+\r\n if (window.getSelection) {\n selectedText = window.getSelection().toString();\n }\r\n\r\n return selectedText;\n };\r\n\r\n /** Opens buttons block */\r\n inline.showButtons = function () {\n var buttons = editor.nodes.inlineToolbar.buttons;\r\n\r\n buttons.classList.add('opened');\r\n\r\n editor.toolbar.inline.buttonsOpened = true;\r\n\r\n /** highlight buttons */\r\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n };\r\n\r\n /** Makes buttons disappear */\r\n inline.closeButtons = function () {\n var buttons = editor.nodes.inlineToolbar.buttons;\r\n\r\n buttons.classList.remove('opened');\r\n\r\n editor.toolbar.inline.buttonsOpened = false;\n };\r\n\r\n /** Open buttons defined action if exist */\r\n inline.showActions = function () {\n var action = editor.nodes.inlineToolbar.actions;\r\n\r\n action.classList.add('opened');\r\n\r\n editor.toolbar.inline.actionsOpened = true;\n };\r\n\r\n /** Close actions block */\r\n inline.closeAction = function () {\n var action = editor.nodes.inlineToolbar.actions;\r\n\r\n action.innerHTML = '';\r\n action.classList.remove('opened');\r\n editor.toolbar.inline.actionsOpened = false;\n };\r\n\r\n\r\n /**\r\n * Callback for keydowns in inline toolbar \"Insert link...\" input\r\n */\r\n let inlineToolbarAnchorInputKeydown_ = function (event) {\n if (event.keyCode != editor.core.keys.ENTER) {\n return;\n }\r\n\r\n let editable = editor.content.currentNode,\r\n storedSelection = editor.toolbar.inline.storedSelection;\r\n\r\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\r\n editor.toolbar.inline.setAnchor(this.value);\r\n\r\n /**\r\n * Preventing events that will be able to happen\r\n */\r\n event.preventDefault();\r\n event.stopImmediatePropagation();\r\n\r\n editor.toolbar.inline.clearRange();\n };\r\n\r\n /** Action for link creation or for setting anchor */\r\n inline.createLinkAction = function (event) {\n var isActive = this.isLinkActive();\r\n\r\n var editable = editor.content.currentNode,\r\n storedSelection = editor.toolbar.inline.saveSelection(editable);\r\n\r\n /** Save globally selection */\r\n editor.toolbar.inline.storedSelection = storedSelection;\r\n\r\n if (isActive) {\n /**\r\n * Changing stored selection. if we want to remove anchor from word\r\n * we should remove anchor from whole word, not only selected part.\r\n * The solution is than we get the length of current link\r\n * Change start position to - end of selection minus length of anchor\r\n */\r\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\r\n\r\n editor.toolbar.inline.defaultToolAction('unlink');\n } else {\n /** Create input and close buttons */\r\n var action = editor.draw.inputForLink();\r\n\r\n editor.nodes.inlineToolbar.actions.appendChild(action);\r\n\r\n editor.toolbar.inline.closeButtons();\r\n editor.toolbar.inline.showActions();\r\n\r\n /**\r\n * focus to input\r\n * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\r\n * Prevents event after showing input and when we need to focus an input which is in unexisted form\r\n */\r\n action.focus();\r\n event.preventDefault();\r\n\r\n /** Callback to link action */\r\n editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);\n }\n };\r\n\r\n inline.isLinkActive = function () {\n var isActive = false;\r\n\r\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\n var dataType = tool.dataset.type;\r\n\r\n if (dataType == 'link' && tool.classList.contains('hightlighted')) {\n isActive = true;\n }\n });\r\n\r\n return isActive;\n };\r\n\r\n /** default action behavior of tool */\r\n inline.defaultToolAction = function (type) {\n document.execCommand(type, false, null);\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Sets URL\r\n *\r\n * @param {String} url - URL\r\n */\r\n inline.setAnchor = function (url) {\n document.execCommand('createLink', false, url);\r\n\r\n /** Close after URL inserting */\r\n editor.toolbar.inline.closeAction();\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Saves selection\r\n */\r\n inline.saveSelection = function (containerEl) {\n var range = window.getSelection().getRangeAt(0),\r\n preSelectionRange = range.cloneRange(),\r\n start;\r\n\r\n preSelectionRange.selectNodeContents(containerEl);\r\n preSelectionRange.setEnd(range.startContainer, range.startOffset);\r\n\r\n start = preSelectionRange.toString().length;\r\n\r\n return {\r\n start: start,\r\n end: start + range.toString().length\r\n };\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Sets to previous selection (Range)\r\n *\r\n * @param {Element} containerEl - editable element where we restore range\r\n * @param {Object} savedSel - range basic information to restore\r\n */\r\n inline.restoreSelection = function (containerEl, savedSel) {\n var range = document.createRange(),\r\n charIndex = 0;\r\n\r\n range.setStart(containerEl, 0);\r\n range.collapse(true);\r\n\r\n var nodeStack = [ containerEl ],\r\n node,\r\n foundStart = false,\r\n stop = false,\r\n nextCharIndex;\r\n\r\n while (!stop && (node = nodeStack.pop())) {\n if (node.nodeType == 3) {\n nextCharIndex = charIndex + node.length;\r\n\r\n if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\n range.setStart(node, savedSel.start - charIndex);\r\n foundStart = true;\n }\r\n if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\n range.setEnd(node, savedSel.end - charIndex);\r\n stop = true;\n }\r\n charIndex = nextCharIndex;\n } else {\n var i = node.childNodes.length;\r\n\r\n while (i--) {\n nodeStack.push(node.childNodes[i]);\n }\n }\n }\r\n\r\n var sel = window.getSelection();\r\n\r\n sel.removeAllRanges();\r\n sel.addRange(range);\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Removes all ranges from window selection\r\n */\r\n inline.clearRange = function () {\n var selection = window.getSelection();\r\n\r\n selection.removeAllRanges();\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * sets or removes hightlight\r\n */\r\n inline.hightlight = function (tool) {\n var dataType = tool.dataset.type;\r\n\r\n if (document.queryCommandState(dataType)) {\n editor.toolbar.inline.setButtonHighlighted(tool);\n } else {\n editor.toolbar.inline.removeButtonsHighLight(tool);\n }\r\n\r\n /**\r\n *\r\n * hightlight for anchors\r\n */\r\n var selection = window.getSelection(),\r\n tag = selection.anchorNode.parentNode;\r\n\r\n if (tag.tagName == 'A' && dataType == 'link') {\n editor.toolbar.inline.setButtonHighlighted(tool);\n }\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Mark button if text is already executed\r\n */\r\n inline.setButtonHighlighted = function (button) {\n button.classList.add('hightlighted');\r\n\r\n /** At link tool we also change icon */\r\n if (button.dataset.type == 'link') {\n var icon = button.childNodes[0];\r\n\r\n icon.classList.remove('ce-icon-link');\r\n icon.classList.add('ce-icon-unlink');\n }\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Removes hightlight\r\n */\r\n inline.removeButtonsHighLight = function (button) {\n button.classList.remove('hightlighted');\r\n\r\n /** At link tool we also change icon */\r\n if (button.dataset.type == 'link') {\n var icon = button.childNodes[0];\r\n\r\n icon.classList.remove('ce-icon-unlink');\r\n icon.classList.add('ce-icon-link');\n }\n };\r\n\r\n\r\n return inline;\n})({});","/**\r\n * Toolbar settings\r\n *\r\n * @version 1.0.5\r\n */\r\n\r\nmodule.exports = (function (settings) {\n let editor = codex.editor;\r\n\r\n settings.opened = false;\r\n\r\n settings.setting = null;\r\n settings.actions = null;\r\n\r\n /**\r\n * Append and open settings\r\n */\r\n settings.open = function (toolType) {\n /**\r\n * Append settings content\r\n * It's stored in tool.settings\r\n */\r\n if ( !editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {\n return;\n }\r\n\r\n /**\r\n * Draw settings block\r\n */\r\n var settingsBlock = editor.tools[toolType].makeSettings();\r\n\r\n editor.nodes.pluginSettings.appendChild(settingsBlock);\r\n\r\n\r\n /** Open settings block */\r\n editor.nodes.blockSettings.classList.add('opened');\r\n this.opened = true;\n };\r\n\r\n /**\r\n * Close and clear settings\r\n */\r\n settings.close = function () {\n editor.nodes.blockSettings.classList.remove('opened');\r\n editor.nodes.pluginSettings.innerHTML = '';\r\n\r\n this.opened = false;\n };\r\n\r\n /**\r\n * @param {string} toolType - plugin type\r\n */\r\n settings.toggle = function ( toolType ) {\n if ( !this.opened ) {\n this.open(toolType);\n } else {\n this.close();\n }\n };\r\n\r\n /**\r\n * Here we will draw buttons and add listeners to components\r\n */\r\n settings.makeRemoveBlockButton = function () {\n var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}),\r\n settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML : '' }),\r\n actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\r\n confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }),\r\n cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' });\r\n\r\n editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\r\n\r\n editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\r\n\r\n editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\r\n\r\n actionWrapper.appendChild(confirmAction);\r\n actionWrapper.appendChild(cancelAction);\r\n\r\n removeBlockWrapper.appendChild(settingButton);\r\n removeBlockWrapper.appendChild(actionWrapper);\r\n\r\n /** Save setting */\r\n editor.toolbar.settings.setting = settingButton;\r\n editor.toolbar.settings.actions = actionWrapper;\r\n\r\n return removeBlockWrapper;\n };\r\n\r\n settings.removeButtonClicked = function () {\n var action = editor.toolbar.settings.actions;\r\n\r\n if (action.classList.contains('opened')) {\n editor.toolbar.settings.hideRemoveActions();\n } else {\n editor.toolbar.settings.showRemoveActions();\n }\r\n\r\n editor.toolbar.toolbox.close();\r\n editor.toolbar.settings.close();\n };\r\n\r\n settings.cancelRemovingRequest = function () {\n editor.toolbar.settings.actions.classList.remove('opened');\n };\r\n\r\n settings.confirmRemovingRequest = function () {\n var currentBlock = editor.content.currentNode,\r\n firstLevelBlocksCount;\r\n\r\n currentBlock.remove();\r\n\r\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\r\n\r\n /**\r\n * If all blocks are removed\r\n */\r\n if (firstLevelBlocksCount === 0) {\n /** update currentNode variable */\r\n editor.content.currentNode = null;\r\n\r\n /** Inserting new empty initial block */\r\n editor.ui.addInitialBlock();\n }\r\n\r\n editor.ui.saveInputs();\r\n\r\n editor.toolbar.close();\n };\r\n\r\n settings.showRemoveActions = function () {\n editor.toolbar.settings.actions.classList.add('opened');\n };\r\n\r\n settings.hideRemoveActions = function () {\n editor.toolbar.settings.actions.classList.remove('opened');\n };\r\n\r\n return settings;\n})({});\r\n","/**\r\n * Codex Editor toolbar module\r\n *\r\n * Contains:\r\n * - Inline toolbox\r\n * - Toolbox within plus button\r\n * - Settings section\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = (function (toolbar) {\n let editor = codex.editor;\r\n\r\n toolbar.settings = require('./settings');\r\n toolbar.inline = require('./inline');\r\n toolbar.toolbox = require('./toolbox');\r\n\r\n /**\r\n * Margin between focused node and toolbar\r\n */\r\n toolbar.defaultToolbarHeight = 49;\r\n\r\n toolbar.defaultOffset = 34;\r\n\r\n toolbar.opened = false;\r\n\r\n toolbar.current = null;\r\n\r\n /**\r\n * @protected\r\n */\r\n toolbar.open = function () {\n if (editor.hideToolbar) {\n return;\n }\r\n\r\n let toolType = editor.content.currentNode.dataset.tool;\r\n\r\n if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {\n editor.nodes.showSettingsButton.classList.add('hide');\n } else {\n editor.nodes.showSettingsButton.classList.remove('hide');\n }\r\n\r\n editor.nodes.toolbar.classList.add('opened');\r\n this.opened = true;\n };\r\n\r\n /**\r\n * @protected\r\n */\r\n toolbar.close = function () {\n editor.nodes.toolbar.classList.remove('opened');\r\n\r\n toolbar.opened = false;\r\n toolbar.current = null;\r\n\r\n for (var button in editor.nodes.toolbarButtons) {\n editor.nodes.toolbarButtons[button].classList.remove('selected');\n }\r\n\r\n /** Close toolbox when toolbar is not displayed */\r\n editor.toolbar.toolbox.close();\r\n editor.toolbar.settings.close();\n };\r\n\r\n toolbar.toggle = function () {\n if ( !this.opened ) {\n this.open();\n } else {\n this.close();\n }\n };\r\n\r\n toolbar.hidePlusButton = function () {\n editor.nodes.plusButton.classList.add('hide');\n };\r\n\r\n toolbar.showPlusButton = function () {\n editor.nodes.plusButton.classList.remove('hide');\n };\r\n\r\n /**\r\n * Moving toolbar to the specified node\r\n */\r\n toolbar.move = function () {\n /** Close Toolbox when we move toolbar */\r\n editor.toolbar.toolbox.close();\r\n\r\n if (!editor.content.currentNode) {\n return;\n }\r\n\r\n var newYCoordinate = editor.content.currentNode.offsetTop - (editor.toolbar.defaultToolbarHeight / 2) + editor.toolbar.defaultOffset;\r\n\r\n editor.nodes.toolbar.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;\r\n\r\n /** Close trash actions */\r\n editor.toolbar.settings.hideRemoveActions();\n };\r\n\r\n return toolbar;\n})({});\r\n","/**\r\n * Codex Editor toolbox\r\n *\r\n * All tools be able to appended here\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = (function (toolbox) {\n let editor = codex.editor;\r\n\r\n toolbox.opened = false;\r\n toolbox.openedOnBlock = null;\r\n\r\n /** Shows toolbox */\r\n toolbox.open = function () {\n /** Close setting if toolbox is opened */\r\n if (editor.toolbar.settings.opened) {\n editor.toolbar.settings.close();\n }\r\n\r\n /** Add 'toolbar-opened' class for current block **/\r\n toolbox.openedOnBlock = editor.content.currentNode;\r\n toolbox.openedOnBlock.classList.add('toolbar-opened');\r\n\r\n /** display toolbox */\r\n editor.nodes.toolbox.classList.add('opened');\r\n\r\n /** Animate plus button */\r\n editor.nodes.plusButton.classList.add('clicked');\r\n\r\n /** toolbox state */\r\n editor.toolbar.toolbox.opened = true;\n };\r\n\r\n /** Closes toolbox */\r\n toolbox.close = function () {\n /** Remove 'toolbar-opened' class from current block **/\r\n if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened');\r\n toolbox.openedOnBlock = null;\r\n\r\n /** Makes toolbox disappear */\r\n editor.nodes.toolbox.classList.remove('opened');\r\n\r\n /** Rotate plus button */\r\n editor.nodes.plusButton.classList.remove('clicked');\r\n\r\n /** toolbox state */\r\n editor.toolbar.toolbox.opened = false;\r\n\r\n editor.toolbar.current = null;\n };\r\n\r\n toolbox.leaf = function () {\n let currentTool = editor.toolbar.current,\r\n tools = Object.keys(editor.tools),\r\n barButtons = editor.nodes.toolbarButtons,\r\n nextToolIndex = 0,\r\n toolToSelect,\r\n visibleTool,\r\n tool;\r\n\r\n if ( !currentTool ) {\n /** Get first tool from object*/\r\n for(tool in editor.tools) {\n if (editor.tools[tool].displayInToolbox) {\n break;\n }\r\n\r\n nextToolIndex ++;\n }\n } else {\n nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;\r\n visibleTool = tools[nextToolIndex];\r\n\r\n while (!editor.tools[visibleTool].displayInToolbox) {\n nextToolIndex = (nextToolIndex + 1) % tools.length;\r\n visibleTool = tools[nextToolIndex];\n }\n }\r\n\r\n toolToSelect = tools[nextToolIndex];\r\n\r\n for ( var button in barButtons ) {\n barButtons[button].classList.remove('selected');\n }\r\n\r\n barButtons[toolToSelect].classList.add('selected');\r\n editor.toolbar.current = toolToSelect;\n };\r\n\r\n /**\r\n * Transforming selected node type into selected toolbar element type\r\n * @param {event} event\r\n */\r\n toolbox.toolClicked = function (event) {\n /**\r\n * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty\r\n */\r\n var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],\r\n tool = editor.tools[editor.toolbar.current],\r\n workingNode = editor.content.currentNode,\r\n currentInputIndex = editor.caret.inputIndex,\r\n newBlockContent,\r\n appendCallback,\r\n blockData;\r\n\r\n /** Make block from plugin */\r\n newBlockContent = tool.render();\r\n\r\n /** information about block */\r\n blockData = {\r\n block : newBlockContent,\r\n type : tool.type,\r\n stretched : false\r\n };\r\n\r\n if (\r\n workingNode &&\r\n UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 &&\r\n workingNode.textContent.trim() === ''\r\n ) {\n /** Replace current block */\r\n editor.content.switchBlock(workingNode, newBlockContent, tool.type);\n } else {\n /** Insert new Block from plugin */\r\n editor.content.insertBlock(blockData);\r\n\r\n /** increase input index */\r\n currentInputIndex++;\n }\r\n\r\n /** Fire tool append callback */\r\n appendCallback = tool.appendCallback;\r\n\r\n if (appendCallback && typeof appendCallback == 'function') {\n appendCallback.call(event);\n }\r\n\r\n window.setTimeout(function () {\n /** Set caret to current block */\r\n editor.caret.setToBlock(currentInputIndex);\n }, 10);\r\n\r\n\r\n /**\r\n * Changing current Node\r\n */\r\n editor.content.workingNodeChanged();\r\n\r\n /**\r\n * Move toolbar when node is changed\r\n */\r\n editor.toolbar.move();\n };\r\n\r\n return toolbox;\n})({});","/**\r\n * @module Codex Editor Tools Submodule\r\n *\r\n * Creates Instances from Plugins and binds external config to the instances\r\n */\r\n\r\n/**\r\n * Each Tool must contain the following important objects:\r\n *\r\n * @typedef {Object} ToolConfig {@link docs/tools.md}\r\n * @property {String} iconClassname - this a icon in toolbar\r\n * @property {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\r\n * @property {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\r\n * @property {Boolean|String[]} inlineToolbar - Pass `true` to enable the Inline Toolbar with all Tools, all pass an array with specified Tools list |\r\n * @property render @todo add description\r\n * @property save @todo add description\r\n * @property settings @todo add description\r\n * @property validate - method that validates output data before saving\r\n */\r\n\r\n/**\r\n * @typedef {Function} Tool {@link docs/tools.md}\r\n * @property {Boolean} displayInToolbox - By default, tools won't be added in the Toolbox. Pass true to add.\r\n * @property {String} iconClassName - CSS class name for the Toolbox button\r\n * @property {Boolean} irreplaceable - Toolbox behaviour: replace or add new block below\r\n * @property render\r\n * @property save\r\n * @property settings\r\n * @property validate\r\n *\r\n * @todo update according to current API\r\n * @todo describe Tool in the {@link docs/tools.md}\r\n */\r\n\r\n/**\r\n * Class properties:\r\n *\r\n * @typedef {Tools} Tools\r\n * @property {Tools[]} toolsAvailable - available Tools\r\n * @property {Tools[]} toolsUnavailable - unavailable Tools\r\n * @property {Object} toolsClasses - all classes\r\n * @property {EditorConfig} config - Editor config\r\n */\r\nexport default class Tools extends Module {\r\n /**\r\n * Returns available Tools\r\n * @return {Tool[]}\r\n */\r\n get available() {\r\n return this.toolsAvailable;\r\n }\r\n\r\n /**\r\n * Returns unavailable Tools\r\n * @return {Tool[]}\r\n */\r\n get unavailable() {\r\n return this.toolsUnavailable;\r\n }\r\n\r\n /**\r\n * Return Tools for the Inline Toolbar\r\n * @return {Array} - array of Inline Tool's classes\r\n */\r\n get inline() {\r\n return Object.values(this.available).filter( tool => {\r\n if (!tool[this.apiSettings.IS_INLINE]) {\r\n return false;\r\n }\r\n\r\n /**\r\n * Some Tools validation\r\n */\r\n const inlineToolRequiredMethods = ['render', 'surround', 'checkState'];\r\n const notImplementedMethods = inlineToolRequiredMethods.filter( method => !new tool()[method] );\r\n\r\n if (notImplementedMethods.length) {\r\n _.log(`Incorrect Inline Tool: ${tool.name}. Some of required methods is not implemented %o`, 'warn', notImplementedMethods);\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n /**\r\n * Constant for available Tools Settings\r\n * @return {object}\r\n */\r\n get apiSettings() {\r\n return {\r\n IS_INLINE: 'isInline',\r\n TOOLBAR_ICON_CLASS: 'iconClassName',\r\n IS_DISPLAYED_IN_TOOLBOX: 'displayInToolbox',\r\n IS_ENABLED_LINE_BREAKS: 'enableLineBreaks',\r\n IS_IRREPLACEBLE_TOOL: 'irreplaceable',\r\n IS_ENABLED_INLINE_TOOLBAR: 'inlineToolbar',\r\n };\r\n }\r\n\r\n /**\r\n * Static getter for default Tool config fields\r\n * @return {ToolConfig}\r\n */\r\n get defaultConfig() {\r\n return {\r\n [this.apiSettings.TOOLBAR_ICON_CLASS] : false,\r\n [this.apiSettings.IS_DISPLAYED_IN_TOOLBOX] : false,\r\n [this.apiSettings.IS_ENABLED_LINE_BREAKS] : false,\r\n [this.apiSettings.IS_IRREPLACEBLE_TOOL] : false,\r\n [this.apiSettings.IS_ENABLED_INLINE_TOOLBAR]: false,\r\n };\r\n }\r\n\r\n /**\r\n * @constructor\r\n *\r\n * @param {EditorConfig} config\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n /**\r\n * Map {name: Class, ...} where:\r\n * name — block type name in JSON. Got from EditorConfig.tools keys\r\n * @type {Object}\r\n */\r\n this.toolClasses = {};\r\n\r\n /**\r\n * Available tools list\r\n * {name: Class, ...}\r\n * @type {Object}\r\n */\r\n this.toolsAvailable = {};\r\n\r\n /**\r\n * Tools that rejected a prepare method\r\n * {name: Class, ... }\r\n * @type {Object}\r\n */\r\n this.toolsUnavailable = {};\r\n }\r\n\r\n /**\r\n * Creates instances via passed or default configuration\r\n * @return {Promise}\r\n */\r\n prepare() {\r\n if (!this.config.hasOwnProperty('tools')) {\r\n return Promise.reject(\"Can't start without tools\");\r\n }\r\n\r\n for(let toolName in this.config.tools) {\r\n this.toolClasses[toolName] = this.config.tools[toolName];\r\n }\r\n\r\n /**\r\n * getting classes that has prepare method\r\n */\r\n let sequenceData = this.getListOfPrepareFunctions();\r\n\r\n /**\r\n * if sequence data contains nothing then resolve current chain and run other module prepare\r\n */\r\n if (sequenceData.length === 0) {\r\n return Promise.resolve();\r\n }\r\n\r\n /**\r\n * to see how it works {@link Util#sequence}\r\n */\r\n return _.sequence(sequenceData, (data) => {\r\n this.success(data);\r\n }, (data) => {\r\n this.fallback(data);\r\n });\r\n }\r\n\r\n /**\r\n * Binds prepare function of plugins with user or default config\r\n * @return {Array} list of functions that needs to be fired sequentially\r\n */\r\n getListOfPrepareFunctions() {\r\n let toolPreparationList = [];\r\n\r\n for(let toolName in this.toolClasses) {\r\n let toolClass = this.toolClasses[toolName];\r\n\r\n if (typeof toolClass.prepare === 'function') {\r\n toolPreparationList.push({\r\n function : toolClass.prepare,\r\n data : {\r\n toolName\r\n }\r\n });\r\n } else {\r\n /**\r\n * If Tool hasn't a prepare method, mark it as available\r\n */\r\n this.toolsAvailable[toolName] = toolClass;\r\n }\r\n }\r\n\r\n return toolPreparationList;\r\n }\r\n\r\n /**\r\n * @param {ChainData.data} data - append tool to available list\r\n */\r\n success(data) {\r\n this.toolsAvailable[data.toolName] = this.toolClasses[data.toolName];\r\n }\r\n\r\n /**\r\n * @param {ChainData.data} data - append tool to unavailable list\r\n */\r\n fallback(data) {\r\n this.toolsUnavailable[data.toolName] = this.toolClasses[data.toolName];\r\n }\r\n\r\n /**\r\n * Return tool`a instance\r\n *\r\n * @param {String} tool — tool name\r\n * @param {Object} data — initial data\r\n *\r\n * @todo throw exceptions if tool doesnt exist\r\n *\r\n */\r\n construct(tool, data) {\r\n let plugin = this.toolClasses[tool],\r\n config = this.config.toolsConfig[tool];\r\n\r\n let instance = new plugin(data, config || {});\r\n\r\n return instance;\r\n }\r\n\r\n /**\r\n * Check if passed Tool is an instance of Initial Block Tool\r\n * @param {Tool} tool - Tool to check\r\n * @return {Boolean}\r\n */\r\n isInitial(tool) {\r\n return tool instanceof this.available[this.config.initialBlock];\r\n }\r\n}\r\n","/**\r\n * Module UI\r\n *\r\n * @type {UI}\r\n */\r\n\r\n/**\r\n * Prebuilded sprite of SVG icons\r\n */\r\nimport sprite from '../../../build/sprite.svg';\r\n\r\n/**\r\n * @class\r\n *\r\n * @classdesc Makes CodeX Editor UI:\r\n * \r\n * \r\n * \r\n * \r\n * \r\n *\r\n * @typedef {UI} UI\r\n * @property {EditorConfig} config - editor configuration {@link CodexEditor#configuration}\r\n * @property {Object} Editor - available editor modules {@link CodexEditor#moduleInstances}\r\n * @property {Object} nodes -\r\n * @property {Element} nodes.holder - element where we need to append redactor\r\n * @property {Element} nodes.wrapper - \r\n * @property {Element} nodes.redactor - \r\n */\r\nexport default class UI extends Module {\r\n /**\r\n * @constructor\r\n *\r\n * @param {EditorConfig} config\r\n */\r\n constructor({config}) {\r\n super({config});\r\n\r\n this.nodes = {\r\n holder: null,\r\n wrapper: null,\r\n redactor: null\r\n };\r\n }\r\n\r\n /**\r\n * Making main interface\r\n */\r\n prepare() {\r\n return this.make()\r\n /**\r\n * Append SVG sprite\r\n */\r\n .then(() => this.appendSVGSprite())\r\n /**\r\n * Make toolbar\r\n */\r\n .then(() => this.Editor.Toolbar.make())\r\n /**\r\n * Make the Inline toolbar\r\n */\r\n .then(() => this.Editor.InlineToolbar.make())\r\n /**\r\n * Load and append CSS\r\n */\r\n .then(() => this.loadStyles())\r\n /**\r\n * Bind events for the UI elements\r\n */\r\n .then(() => this.bindEvents())\r\n\r\n /** Make container for inline toolbar */\r\n // .then(makeInlineToolbar_)\r\n\r\n /** Add inline toolbar tools */\r\n // .then(addInlineToolbarTools_)\r\n\r\n /** Draw wrapper for notifications */\r\n // .then(makeNotificationHolder_)\r\n\r\n /** Add eventlisteners to redactor elements */\r\n // .then(bindEvents_)\r\n\r\n .catch(e => {\r\n console.error(e);\r\n\r\n // editor.core.log(\"Can't draw editor interface\");\r\n });\r\n }\r\n\r\n /**\r\n * CodeX Editor UI CSS class names\r\n * @return {{editorWrapper: string, editorZone: string, block: string}}\r\n */\r\n get CSS() {\r\n return {\r\n editorWrapper : 'codex-editor',\r\n editorZone : 'codex-editor__redactor',\r\n };\r\n }\r\n\r\n /**\r\n * Makes CodeX Editor interface\r\n * @return {Promise}\r\n */\r\n make() {\r\n return new Promise( (resolve, reject) => {\r\n /**\r\n * Element where we need to append CodeX Editor\r\n * @type {Element}\r\n */\r\n this.nodes.holder = document.getElementById(this.config.holderId);\r\n\r\n if (!this.nodes.holder) {\r\n reject(Error(\"Holder wasn't found by ID: #\" + this.config.holderId));\r\n return;\r\n }\r\n\r\n /**\r\n * Create and save main UI elements\r\n */\r\n this.nodes.wrapper = $.make('div', this.CSS.editorWrapper);\r\n this.nodes.redactor = $.make('div', this.CSS.editorZone);\r\n\r\n this.nodes.wrapper.appendChild(this.nodes.redactor);\r\n this.nodes.holder.appendChild(this.nodes.wrapper);\r\n\r\n resolve();\r\n });\r\n }\r\n\r\n /**\r\n * Appends CSS\r\n */\r\n loadStyles() {\r\n /**\r\n * Load CSS\r\n */\r\n let styles = require('../../styles/main.css');\r\n\r\n /**\r\n * Make tag\r\n */\r\n let tag = $.make('style', null, {\r\n textContent: styles.toString()\r\n });\r\n\r\n /**\r\n * Append styles\r\n */\r\n $.append(document.head, tag);\r\n }\r\n\r\n /**\r\n * Bind events on the CodeX Editor interface\r\n */\r\n bindEvents() {\r\n this.Editor.Listeners.on(this.nodes.redactor, 'click', event => this.redactorClicked(event), false );\r\n this.Editor.Listeners.on(document, 'click', event => this.documentClicked(event), false );\r\n }\r\n\r\n /**\r\n * All clicks on document\r\n * @param {MouseEvent} event - Click\r\n */\r\n documentClicked(event) {\r\n /**\r\n * Close Inline Toolbar when nothing selected\r\n * Do not fire check on clicks at the Inline Toolbar buttons\r\n */\r\n const clickedOnInlineToolbarButton = event.target.closest(`.${this.Editor.InlineToolbar.CSS.inlineToolbar}`);\r\n\r\n if (!clickedOnInlineToolbarButton) {\r\n this.Editor.InlineToolbar.handleShowingEvent(event);\r\n }\r\n }\r\n\r\n /**\r\n * All clicks on the redactor zone\r\n *\r\n * @param {MouseEvent} event\r\n *\r\n * @description\r\n * 1. Save clicked Block as a current {@link BlockManager#currentNode}\r\n * it uses for the following:\r\n * - add CSS modifier for the selected Block\r\n * - on Enter press, we make a new Block under that\r\n *\r\n * 2. Move and show the Toolbar\r\n *\r\n * 3. Set a Caret\r\n *\r\n * 4. By clicks on the Editor's bottom zone:\r\n * - if last Block is empty, set a Caret to this\r\n * - otherwise, add a new empty Block and set a Caret to that\r\n *\r\n * 5. Hide the Inline Toolbar\r\n *\r\n * @see selectClickedBlock\r\n *\r\n */\r\n redactorClicked(event) {\r\n let clickedNode = event.target;\r\n\r\n /**\r\n * Select clicked Block as Current\r\n */\r\n try {\r\n this.Editor.BlockManager.setCurrentBlockByChildNode(clickedNode);\r\n } catch (e) {\r\n /**\r\n * If clicked outside first-level Blocks, set Caret to the last empty Block\r\n */\r\n this.Editor.Caret.setToTheLastBlock();\r\n }\r\n\r\n /**\r\n *\r\n\r\n /** Update current input index in memory when caret focused into existed input */\r\n // if (event.target.contentEditable == 'true') {\r\n //\r\n // editor.caret.saveCurrentInputIndex();\r\n //\r\n // }\r\n\r\n // if (editor.content.currentNode === null) {\r\n //\r\n // /**\r\n // * If inputs in redactor does not exits, then we put input index 0 not -1\r\n // */\r\n // var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0;\r\n //\r\n // /** If we have any inputs */\r\n // if (editor.state.inputs.length) {\r\n //\r\n // /** getting firstlevel parent of input */\r\n // firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);\r\n //\r\n // }\r\n //\r\n // /** If input is empty, then we set caret to the last input */\r\n // if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {\r\n //\r\n // editor.caret.setToBlock(indexOfLastInput);\r\n //\r\n // } else {\r\n //\r\n // /** Create new input when caret clicked in redactors area */\r\n // var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\r\n //\r\n // editor.content.insertBlock({\r\n // type : NEW_BLOCK_TYPE,\r\n // block : editor.tools[NEW_BLOCK_TYPE].render()\r\n // });\r\n //\r\n // /** If there is no inputs except inserted */\r\n // if (editor.state.inputs.length === 1) {\r\n //\r\n // editor.caret.setToBlock(indexOfLastInput);\r\n //\r\n // } else {\r\n //\r\n // /** Set caret to this appended input */\r\n // editor.caret.setToNextBlock(indexOfLastInput);\r\n //\r\n // }\r\n //\r\n // }\r\n //\r\n // } else {\r\n //\r\n // /** Close all panels */\r\n // editor.toolbar.settings.close();\r\n // editor.toolbar.toolbox.close();\r\n //\r\n // }\r\n //\r\n /**\r\n * Move toolbar and open\r\n */\r\n this.Editor.Toolbar.move();\r\n this.Editor.Toolbar.open();\r\n //\r\n // var inputIsEmpty = !editor.content.currentNode.textContent.trim(),\r\n // currentNodeType = editor.content.currentNode.dataset.tool,\r\n // isInitialType = currentNodeType == editor.settings.initialBlockPlugin;\r\n //\r\n //\r\n\r\n /**\r\n * Hide the Plus Button\r\n * */\r\n this.Editor.Toolbar.plusButton.hide();\r\n\r\n /**\r\n * Show the Plus Button if:\r\n * - Block is an initial-block (Text)\r\n * - Block is empty\r\n */\r\n let isInitialBlock = this.Editor.Tools.isInitial(this.Editor.BlockManager.currentBlock.tool),\r\n isEmptyBlock = this.Editor.BlockManager.currentBlock.isEmpty;\r\n\r\n if (isInitialBlock && isEmptyBlock) {\r\n this.Editor.Toolbar.plusButton.show();\r\n }\r\n }\r\n\r\n /**\r\n * Append prebuilded sprite with SVG icons\r\n */\r\n appendSVGSprite() {\r\n let spriteHolder = $.make('div');\r\n\r\n spriteHolder.innerHTML = sprite;\r\n\r\n $.append(this.nodes.wrapper, spriteHolder);\r\n }\r\n}\r\n\r\n// /**\r\n// * Codex Editor UI module\r\n// *\r\n// * @author Codex Team\r\n// * @version 1.2.0\r\n// */\r\n//\r\n// module.exports = (function (ui) {\r\n//\r\n// let editor = codex.editor;\r\n//\r\n// /**\r\n// * Basic editor classnames\r\n// */\r\n// ui.prepare = function () {\r\n//\r\n\r\n//\r\n// };\r\n//\r\n// /** Draw notifications holder */\r\n// var makeNotificationHolder_ = function () {\r\n//\r\n// /** Append block with notifications to the document */\r\n// editor.nodes.notifications = editor.notifications.createHolder();\r\n//\r\n// };\r\n//\r\n//\r\n// var addInlineToolbarTools_ = function () {\r\n//\r\n// var tools = {\r\n//\r\n// bold: {\r\n// icon : 'ce-icon-bold',\r\n// command : 'bold'\r\n// },\r\n//\r\n// italic: {\r\n// icon : 'ce-icon-italic',\r\n// command : 'italic'\r\n// },\r\n//\r\n// link: {\r\n// icon : 'ce-icon-link',\r\n// command : 'createLink'\r\n// }\r\n// };\r\n//\r\n// var toolButton,\r\n// tool;\r\n//\r\n// for(var name in tools) {\r\n//\r\n// tool = tools[name];\r\n//\r\n// toolButton = editor.draw.toolbarButtonInline(name, tool.icon);\r\n//\r\n// editor.nodes.inlineToolbar.buttons.appendChild(toolButton);\r\n// /**\r\n// * Add callbacks to this buttons\r\n// */\r\n// editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);\r\n//\r\n// }\r\n//\r\n// };\r\n//\r\n// /**\r\n// * @private\r\n// * Bind editor UI events\r\n// */\r\n// var bindEvents_ = function () {\r\n//\r\n// editor.core.log('ui.bindEvents fired', 'info');\r\n//\r\n// // window.addEventListener('error', function (errorMsg, url, lineNumber) {\r\n// // editor.notifications.errorThrown(errorMsg, event);\r\n// // }, false );\r\n//\r\n// /** All keydowns on Document */\r\n// editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\r\n//\r\n// /** All keydowns on Redactor zone */\r\n// editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\r\n//\r\n// /** All keydowns on Document */\r\n// editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );\r\n//\r\n// /**\r\n// * Mouse click to radactor\r\n// */\r\n// editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );\r\n//\r\n// /**\r\n// * Clicks to the Plus button\r\n// */\r\n// editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\r\n//\r\n// /**\r\n// * Clicks to SETTINGS button in toolbar\r\n// */\r\n// editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );\r\n//\r\n// /** Bind click listeners on toolbar buttons */\r\n// for (var button in editor.nodes.toolbarButtons) {\r\n//\r\n// editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\r\n//\r\n// }\r\n//\r\n// };\r\n//\r\n// ui.addBlockHandlers = function (block) {\r\n//\r\n// if (!block) return;\r\n//\r\n// /**\r\n// * Block keydowns\r\n// */\r\n// editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\r\n//\r\n// /**\r\n// * Pasting content from another source\r\n// * We have two type of sanitization\r\n// * First - uses deep-first search algorithm to get sub nodes,\r\n// * sanitizes whole Block_content and replaces cleared nodes\r\n// * This method is deprecated\r\n// * Method is used in editor.callback.blockPaste(event)\r\n// *\r\n// * Secont - uses Mutation observer.\r\n// * Observer \"observe\" DOM changes and send changings to callback.\r\n// * Callback gets changed node, not whole Block_content.\r\n// * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\r\n// *\r\n// * Method is used in editor.callback.blockPasteViaSanitize(event)\r\n// *\r\n// * @uses html-janitor\r\n// * @example editor.callback.blockPasteViaSanitize(event), the second method.\r\n// *\r\n// */\r\n// editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);\r\n//\r\n// /**\r\n// * Show inline toolbar for selected text\r\n// */\r\n// editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\r\n// editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);\r\n//\r\n// };\r\n//\r\n// /** getting all contenteditable elements */\r\n// ui.saveInputs = function () {\r\n//\r\n// var redactor = editor.nodes.redactor;\r\n//\r\n// editor.state.inputs = [];\r\n//\r\n// /** Save all inputs in global variable state */\r\n// var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\r\n//\r\n// Array.prototype.map.call(inputs, function (current) {\r\n//\r\n// if (!current.type || current.type == 'text' || current.type == 'textarea') {\r\n//\r\n// editor.state.inputs.push(current);\r\n//\r\n// }\r\n//\r\n// });\r\n//\r\n// };\r\n//\r\n// /**\r\n// * Adds first initial block on empty redactor\r\n// */\r\n// ui.addInitialBlock = function () {\r\n//\r\n// var initialBlockType = editor.settings.initialBlockPlugin,\r\n// initialBlock;\r\n//\r\n// if ( !editor.tools[initialBlockType] ) {\r\n//\r\n// editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\r\n// return;\r\n//\r\n// }\r\n//\r\n// initialBlock = editor.tools[initialBlockType].render();\r\n//\r\n// initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);\r\n//\r\n// editor.content.insertBlock({\r\n// type : initialBlockType,\r\n// block : initialBlock\r\n// });\r\n//\r\n// editor.content.workingNodeChanged(initialBlock);\r\n//\r\n// };\r\n//\r\n// ui.setInlineToolbarButtonBehaviour = function (button, type) {\r\n//\r\n// editor.listeners.add(button, 'mousedown', function (event) {\r\n//\r\n// editor.toolbar.inline.toolClicked(event, type);\r\n//\r\n// }, false);\r\n//\r\n// };\r\n//\r\n// return ui;\r\n//\r\n// })({});\r\n","/**\r\n * Element.closest()\r\n *\r\n * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest\r\n */\r\nif (!Element.prototype.matches)\r\n Element.prototype.matches = Element.prototype.msMatchesSelector ||\r\n Element.prototype.webkitMatchesSelector;\r\n\r\nif (!Element.prototype.closest)\r\n Element.prototype.closest = function (s) {\r\n var el = this;\r\n\r\n if (!document.documentElement.contains(el)) return null;\r\n do {\r\n if (el.matches(s)) return el;\r\n el = el.parentElement || el.parentNode;\r\n } while (el !== null);\r\n return null;\r\n };\r\n","/**\r\n * Working with selection\r\n * @typedef {Selection} Selection\r\n */\r\nexport default class Selection {\r\n /**\r\n * @constructor\r\n */\r\n constructor() {\r\n this.instance = null;\r\n this.selection = null;\r\n\r\n /**\r\n * This property can store Selection's range for restoring later\r\n * @type {Range|null}\r\n */\r\n this.savedSelectionRange = null;\r\n }\r\n\r\n /**\r\n * Returns window Selection\r\n * {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}\r\n * @return {Selection}\r\n */\r\n static get() {\r\n return window.getSelection();\r\n }\r\n\r\n /**\r\n * Returns selected anchor\r\n * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorNode}\r\n * @return {Node|null}\r\n */\r\n static get anchorNode() {\r\n const selection = window.getSelection();\r\n\r\n return selection ? selection.anchorNode : null;\r\n }\r\n\r\n /**\r\n * Returns selection offset according to the anchor node\r\n * {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorOffset}\r\n * @return {Number|null}\r\n */\r\n static get anchorOffset() {\r\n const selection = window.getSelection();\r\n\r\n return selection ? selection.anchorOffset : null;\r\n }\r\n\r\n /**\r\n * Is current selection range collapsed\r\n * @return {boolean|null}\r\n */\r\n static get isCollapsed() {\r\n const selection = window.getSelection();\r\n\r\n return selection ? selection.isCollapsed : null;\r\n }\r\n\r\n /**\r\n * Return first range\r\n * @return {Range|null}\r\n */\r\n static get range() {\r\n const selection = window.getSelection();\r\n\r\n return selection && selection.rangeCount ? selection.getRangeAt(0) : null;\r\n }\r\n\r\n /**\r\n * Calculates position and size of selected text\r\n * @return {{x, y, width, height, top?, left?, bottom?, right?}}\r\n */\r\n static get rect() {\r\n let sel = document.selection, range;\r\n let rect = {\r\n x: 0,\r\n y: 0,\r\n width: 0,\r\n height: 0\r\n };\r\n\r\n if (sel && sel.type !== 'Control') {\r\n range = sel.createRange();\r\n rect.x = range.boundingLeft;\r\n rect.y = range.boundingTop;\r\n rect.width = range.boundingWidth;\r\n rect.height = range.boundingHeight;\r\n\r\n return rect;\r\n }\r\n\r\n if (!window.getSelection) {\r\n _.log('Method window.getSelection is not supported', 'warn');\r\n return rect;\r\n }\r\n\r\n sel = window.getSelection();\r\n\r\n if (!sel.rangeCount) {\r\n _.log('Method Selection.rangeCount() is not supported', 'warn');\r\n return rect;\r\n }\r\n\r\n range = sel.getRangeAt(0).cloneRange();\r\n\r\n if (range.getBoundingClientRect) {\r\n rect = range.getBoundingClientRect();\r\n }\r\n // Fall back to inserting a temporary element\r\n if (rect.x === 0 && rect.y === 0) {\r\n let span = document.createElement('span');\r\n\r\n if (span.getBoundingClientRect) {\r\n // Ensure span has dimensions and position by\r\n // adding a zero-width space character\r\n span.appendChild( document.createTextNode('\\u200b') );\r\n range.insertNode(span);\r\n rect = span.getBoundingClientRect();\r\n\r\n let spanParent = span.parentNode;\r\n\r\n spanParent.removeChild(span);\r\n\r\n // Glue any broken text nodes back together\r\n spanParent.normalize();\r\n }\r\n }\r\n\r\n return rect;\r\n }\r\n\r\n /**\r\n * Returns selected text as String\r\n * @returns {string}\r\n */\r\n static get text() {\r\n return window.getSelection ? window.getSelection().toString() : '';\r\n };\r\n\r\n /**\r\n * Save Selection's range\r\n */\r\n save() {\r\n this.savedSelectionRange = Selection.range;\r\n }\r\n\r\n /**\r\n * Restore saved Selection's range\r\n */\r\n restore() {\r\n if (!this.savedSelectionRange) {\r\n return;\r\n }\r\n\r\n const sel = window.getSelection();\r\n\r\n sel.removeAllRanges();\r\n sel.addRange(this.savedSelectionRange);\r\n }\r\n\r\n /**\r\n * Clears saved selection\r\n */\r\n clearSaved() {\r\n this.savedSelectionRange = null;\r\n }\r\n\r\n /**\r\n * Looks ahead to find passed tag from current selection\r\n *\r\n * @param {String} tagName - tag to found\r\n * @param {String} [className] - tag's class name\r\n * @param {Number} [searchDepth] - count of tags that can be included. For better performance.\r\n * @return {HTMLElement|null}\r\n */\r\n findParentTag(tagName, className, searchDepth = 10) {\r\n let selection = window.getSelection(),\r\n parentTag = null;\r\n\r\n /**\r\n * If selection is missing or no anchorNode or focusNode were found then return null\r\n */\r\n if (!selection || !selection.anchorNode || !selection.focusNode) {\r\n return null;\r\n }\r\n\r\n /**\r\n * Define Nodes for start and end of selection\r\n */\r\n let boundNodes = [\r\n /** the Node in which the selection begins */\r\n selection.anchorNode,\r\n /** the Node in which the selection ends */\r\n selection.focusNode\r\n ];\r\n\r\n /**\r\n * For each selection parent Nodes we try to find target tag [with target class name]\r\n * It would be saved in parentTag variable\r\n */\r\n boundNodes.forEach(parent => {\r\n /** Reset tags limit */\r\n let searchDepthIterable = searchDepth;\r\n\r\n while (searchDepthIterable > 0 && parent.parentNode) {\r\n /**\r\n * Check tag's name\r\n */\r\n if (parent.tagName === tagName) {\r\n /**\r\n * Optional additional check for class-name matching\r\n */\r\n if (className && parent.classList && !parent.classList.contains(className)) {\r\n continue;\r\n }\r\n\r\n /**\r\n * If we have found required tag with class then save the result and go out from cycle\r\n */\r\n parentTag = parent;\r\n break;\r\n }\r\n\r\n /**\r\n * Target tag was not found. Go up to the parent and check it\r\n */\r\n parent = parent.parentNode;\r\n searchDepthIterable--;\r\n }\r\n });\r\n\r\n /**\r\n * Return found tag or null\r\n */\r\n return parentTag;\r\n }\r\n\r\n /**\r\n * Expands selection range to the passed parent node\r\n *\r\n * @param {HTMLElement} node\r\n */\r\n expandToTag(node) {\r\n let selection = window.getSelection();\r\n\r\n selection.removeAllRanges();\r\n let range = document.createRange();\r\n\r\n range.selectNodeContents(node);\r\n selection.addRange(range);\r\n }\r\n}\r\n","/**\r\n * Codex Editor Util\r\n */\r\nexport default class Util {\r\n /**\r\n * Custom logger\r\n *\r\n * @param {string} msg - message\r\n * @param {string} type - logging type 'log'|'warn'|'error'|'info'\r\n * @param {*} args - argument to log with a message\r\n */\r\n static log(msg, type, args) {\r\n type = type || 'log';\r\n\r\n if (!args) {\r\n args = msg || 'undefined';\r\n msg = '[codex-editor]: %o';\r\n } else {\r\n msg = '[codex-editor]: ' + msg;\r\n }\r\n\r\n try{\r\n if ( 'console' in window && window.console[ type ] ) {\r\n if ( args ) window.console[ type ]( msg, args );\r\n else window.console[ type ]( msg );\r\n }\r\n } catch(e) {\r\n // do nothing\r\n }\r\n }\r\n\r\n /**\r\n * Returns basic keycodes as constants\r\n * @return {{}}\r\n */\r\n static get keyCodes() {\r\n return {\r\n BACKSPACE: 8,\r\n TAB: 9,\r\n ENTER: 13,\r\n SHIFT: 16,\r\n CTRL: 17,\r\n ALT: 18,\r\n ESC: 27,\r\n SPACE: 32,\r\n LEFT: 37,\r\n UP: 38,\r\n DOWN: 40,\r\n RIGHT: 39,\r\n DELETE: 46,\r\n META: 91\r\n };\r\n }\r\n\r\n /**\r\n * @typedef {Object} ChainData\r\n * @property {Object} data - data that will be passed to the success or fallback\r\n * @property {Function} function - function's that must be called asynchronically\r\n */\r\n\r\n /**\r\n * Fires a promise sequence asyncronically\r\n *\r\n * @param {Object[]} chains - list or ChainData's\r\n * @param {Function} success - success callback\r\n * @param {Function} fallback - callback that fires in case of errors\r\n *\r\n * @return {Promise}\r\n */\r\n static sequence(chains, success = () => {}, fallback = () => {}) {\r\n return new Promise(function (resolve) {\r\n /**\r\n * pluck each element from queue\r\n * First, send resolved Promise as previous value\r\n * Each plugins \"prepare\" method returns a Promise, that's why\r\n * reduce current element will not be able to continue while can't get\r\n * a resolved Promise\r\n */\r\n chains.reduce(function (previousValue, currentValue, iteration) {\r\n return previousValue\r\n .then(() => waitNextBlock(currentValue, success, fallback))\r\n .then(() => {\r\n // finished\r\n if (iteration === chains.length - 1) {\r\n resolve();\r\n }\r\n });\r\n }, Promise.resolve());\r\n });\r\n\r\n /**\r\n * Decorator\r\n *\r\n * @param {ChainData} chainData\r\n *\r\n * @param {Function} successCallback\r\n * @param {Function} fallbackCallback\r\n *\r\n * @return {Promise}\r\n */\r\n function waitNextBlock(chainData, successCallback, fallbackCallback) {\r\n return new Promise(function (resolve) {\r\n chainData.function()\r\n .then(() => {\r\n successCallback(chainData.data || {});\r\n })\r\n .then(resolve)\r\n .catch(function () {\r\n fallbackCallback(chainData.data || {});\r\n\r\n // anyway, go ahead even it falls\r\n resolve();\r\n });\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Make array from array-like collection\r\n *\r\n * @param {*} collection\r\n *\r\n * @return {Array}\r\n */\r\n static array(collection) {\r\n return Array.prototype.slice.call(collection);\r\n }\r\n\r\n /**\r\n * Checks if object is empty\r\n *\r\n * @param {Object} object\r\n * @return {boolean}\r\n */\r\n static isEmpty(object) {\r\n return Object.keys(object).length === 0 && object.constructor === Object;\r\n }\r\n\r\n /**\r\n * Check if passed object is a Promise\r\n * @param {*} object - object to check\r\n * @return {Boolean}\r\n */\r\n static isPromise(object) {\r\n return Promise.resolve(object) === object;\r\n }\r\n\r\n /**\r\n * Check if passed element is contenteditable\r\n * @param element\r\n * @return {boolean}\r\n */\r\n static isContentEditable(element) {\r\n return element.contentEditable === 'true';\r\n }\r\n\r\n /**\r\n * Delays method execution\r\n *\r\n * @param method\r\n * @param timeout\r\n */\r\n static delay(method, timeout) {\r\n return function () {\r\n let context = this,\r\n args = arguments;\r\n\r\n window.setTimeout(() => method.apply(context, args), timeout);\r\n };\r\n }\r\n};\r\n","exports = module.exports = require(\"../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \":root {\\r\\n /**\\r\\n * Toolbar buttons\\r\\n */\\r\\n --bg-light: #eff2f5;\\r\\n\\r\\n /**\\r\\n * All gray texts: placeholders, settings\\r\\n */\\r\\n --grayText: #707684;\\r\\n\\r\\n /** Blue icons */\\r\\n --color-active-icon: #388AE5;\\r\\n\\r\\n /**\\r\\n * Block content width\\r\\n */\\r\\n --content-width: 650px;\\r\\n\\r\\n /**\\r\\n * Toolbar Plus Button and Toolbox buttons height and width\\r\\n */\\r\\n --toolbar-buttons-size: 34px;\\r\\n\\r\\n /**\\r\\n * Confirm deletion bg\\r\\n */\\r\\n --color-confirm: #E24A4A;\\r\\n}\\r\\n/**\\r\\n* Editor wrapper\\r\\n*/\\r\\n.codex-editor {\\r\\n position: relative;\\r\\n box-sizing: border-box;\\r\\n\\r\\n\\r\\n}\\r\\n.codex-editor .hide {\\r\\n display: none;\\r\\n }\\r\\n.codex-editor__redactor {\\r\\n padding-bottom: 300px;\\r\\n }\\r\\n.codex-editor svg {\\r\\n fill: currentColor;\\r\\n vertical-align: middle;\\r\\n max-height: 100%;\\r\\n }\\r\\n::-moz-selection{\\r\\n background-color: rgba(61,166,239,0.63);\\r\\n}\\r\\n::selection{\\r\\n background-color: rgba(61,166,239,0.63);\\r\\n}\\r\\n.ce-tune-moveup{}\\r\\n.ce-settings-delete:hover {\\r\\n cursor: pointer;\\r\\n }\\r\\n.ce-settings-delete::before {\\r\\n content: 'delete'\\r\\n }\\r\\n.ce-toolbar {\\r\\n position: absolute;\\r\\n left: 0;\\r\\n right: 0;\\r\\n top: 0;\\r\\n /*opacity: 0;*/\\r\\n /*visibility: hidden;*/\\r\\n transition: opacity 100ms ease;\\r\\n will-change: opacity, transform;\\r\\n display: none;\\r\\n}\\r\\n.ce-toolbar--opened {\\r\\n display: block;\\r\\n /*opacity: 1;*/\\r\\n /*visibility: visible;*/\\r\\n }\\r\\n.ce-toolbar__content {\\r\\n max-width: 650px;\\r\\n max-width: var(--content-width);\\r\\n margin: 0 auto;\\r\\n position: relative;\\r\\n }\\r\\n.ce-toolbar__plus {\\r\\n position: absolute;\\r\\n left: calc(calc(34px + 10px) * -1);\\r\\n left: calc(calc(var(--toolbar-buttons-size) + 10px) * -1);\\r\\n display: inline-block;\\r\\n background-color: #eff2f5;\\r\\n background-color: var(--bg-light);\\r\\n width: 34px;\\r\\n width: var(--toolbar-buttons-size);\\r\\n height: 34px;\\r\\n height: var(--toolbar-buttons-size);\\r\\n line-height: 34px;\\r\\n text-align: center;\\r\\n border-radius: 50%;\\r\\n cursor: pointer;\\r\\n }\\r\\n.ce-toolbar__plus--hidden {\\r\\n display: none;\\r\\n }\\r\\n/**\\r\\n * Block actions Zone\\r\\n * -------------------------\\r\\n */\\r\\n.ce-toolbar__actions {\\r\\n position: absolute;\\r\\n right: 0;\\r\\n top: 0;\\r\\n padding-right: 16px;\\r\\n }\\r\\n.ce-toolbar__actions-buttons {\\r\\n text-align: right;\\r\\n }\\r\\n.ce-toolbar__settings-btn {\\r\\n display: inline-block;\\r\\n width: 24px;\\r\\n height: 24px;\\r\\n color: #707684;\\r\\n color: var(--grayText);\\r\\n cursor: pointer;\\r\\n }\\r\\n.ce-toolbox {\\r\\n position: absolute;\\r\\n visibility: hidden;\\r\\n transition: opacity 100ms ease;\\r\\n will-change: opacity;\\r\\n}\\r\\n.ce-toolbox--opened {\\r\\n opacity: 1;\\r\\n visibility: visible;\\r\\n }\\r\\n.ce-toolbox__button {\\r\\n display: inline-block;\\r\\n list-style: none;\\r\\n margin: 0;\\r\\n background: #eff2f5;\\r\\n background: var(--bg-light);\\r\\n width: 34px;\\r\\n width: var(--toolbar-buttons-size);\\r\\n height: 34px;\\r\\n height: var(--toolbar-buttons-size);\\r\\n border-radius: 30px;\\r\\n overflow: hidden;\\r\\n text-align: center;\\r\\n line-height: 34px;\\r\\n line-height: var(--toolbar-buttons-size)\\r\\n }\\r\\n.ce-toolbox__button::before {\\r\\n content: attr(title);\\r\\n font-size: 22px;\\r\\n font-weight: 500;\\r\\n letter-spacing: 1em;\\r\\n -webkit-font-feature-settings: \\\"smcp\\\", \\\"c2sc\\\";\\r\\n font-feature-settings: \\\"smcp\\\", \\\"c2sc\\\";\\r\\n font-variant-caps: all-small-caps;\\r\\n padding-left: 11.5px;\\r\\n margin-top: -1px;\\r\\n display: inline-block;\\r\\n }\\r\\n.ce-inline-toolbar {\\r\\n position: absolute;\\r\\n background-color: #FFFFFF;\\r\\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\\r\\n border-radius: 4px;\\r\\n z-index: 2\\r\\n}\\r\\n.ce-inline-toolbar::before {\\r\\n content: '';\\r\\n width: 15px;\\r\\n height: 15px;\\r\\n position: absolute;\\r\\n top: -7px;\\r\\n left: 50%;\\r\\n margin-left: -7px;\\r\\n transform: rotate(-45deg);\\r\\n background-color: #fff;\\r\\n z-index: -1;\\r\\n }\\r\\n.ce-inline-toolbar {\\r\\n padding: 6px;\\r\\n transform: translateX(-50%);\\r\\n display: none;\\r\\n box-shadow: 0 6px 12px -6px rgba(131, 147, 173, 0.46),\\r\\n 5px -12px 34px -13px rgba(97, 105, 134, 0.6),\\r\\n 0 26px 52px 3px rgba(147, 165, 186, 0.24);\\r\\n}\\r\\n.ce-inline-toolbar--showed {\\r\\n display: block;\\r\\n }\\r\\n.ce-inline-tool {\\r\\n display: inline-block;\\r\\n width: 34px;\\r\\n height: 34px;\\r\\n line-height: 34px;\\r\\n text-align: center;\\r\\n border-radius: 3px;\\r\\n cursor: pointer;\\r\\n border: 0;\\r\\n outline: none;\\r\\n background-color: transparent;\\r\\n vertical-align: bottom;\\r\\n color: #707684;\\r\\n color: var(--grayText)\\r\\n}\\r\\n.ce-inline-tool:not(:last-of-type){\\r\\n margin-right: 5px;\\r\\n }\\r\\n.ce-inline-tool:hover {\\r\\n background-color: #eff2f5;\\r\\n background-color: var(--bg-light);\\r\\n }\\r\\n.ce-inline-tool {\\r\\n line-height: normal;\\r\\n}\\r\\n.ce-inline-tool--active {\\r\\n color: #388AE5;\\r\\n color: var(--color-active-icon);\\r\\n }\\r\\n.ce-inline-tool--link .icon {\\r\\n margin-top: -2px;\\r\\n }\\r\\n.ce-inline-tool--link .icon--unlink {\\r\\n display: none;\\r\\n }\\r\\n.ce-inline-tool--unlink .icon--link {\\r\\n display: none;\\r\\n }\\r\\n.ce-inline-tool--unlink .icon--unlink {\\r\\n display: inline-block;\\r\\n }\\r\\n.ce-inline-tool-input {\\r\\n background-color: #eff2f5;\\r\\n background-color: var(--bg-light);\\r\\n outline: none;\\r\\n border: 0;\\r\\n border-radius: 3px;\\r\\n margin: 6px 0 0;\\r\\n font-size: 13px;\\r\\n padding: 8px;\\r\\n width: 100%;\\r\\n box-sizing: border-box;\\r\\n display: none\\r\\n }\\r\\n.ce-inline-tool-input::-webkit-input-placeholder {\\r\\n color: #707684;\\r\\n color: var(--grayText);\\r\\n }\\r\\n.ce-inline-tool-input:-ms-input-placeholder {\\r\\n color: #707684;\\r\\n color: var(--grayText);\\r\\n }\\r\\n.ce-inline-tool-input::placeholder {\\r\\n color: #707684;\\r\\n color: var(--grayText);\\r\\n }\\r\\n.ce-inline-tool-input--showed {\\r\\n display: block;\\r\\n }\\r\\n.ce-settings {\\r\\n position: absolute;\\r\\n background-color: #FFFFFF;\\r\\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\\r\\n border-radius: 4px;\\r\\n z-index: 2\\r\\n}\\r\\n.ce-settings::before {\\r\\n content: '';\\r\\n width: 15px;\\r\\n height: 15px;\\r\\n position: absolute;\\r\\n top: -7px;\\r\\n left: 50%;\\r\\n margin-left: -7px;\\r\\n transform: rotate(-45deg);\\r\\n background-color: #fff;\\r\\n z-index: -1;\\r\\n }\\r\\n.ce-settings {\\r\\n right: 5px;\\r\\n top: 35px;\\r\\n min-width: 124px\\r\\n}\\r\\n.ce-settings::before{\\r\\n left: auto;\\r\\n right: 12px;\\r\\n }\\r\\n.ce-settings {\\r\\n\\r\\n display: none;\\r\\n}\\r\\n.ce-settings--opened {\\r\\n display: block;\\r\\n }\\r\\n.ce-settings__plugin-zone:not(:empty){\\r\\n padding: 6px;\\r\\n }\\r\\n.ce-settings__default-zone:not(:empty){\\r\\n padding: 6px;\\r\\n }\\r\\n.ce-settings__button {\\r\\n display: inline-block;\\r\\n width: 34px;\\r\\n height: 34px;\\r\\n line-height: 34px;\\r\\n text-align: center;\\r\\n border-radius: 3px;\\r\\n cursor: pointer;\\r\\n border: 0;\\r\\n outline: none;\\r\\n background-color: transparent;\\r\\n vertical-align: bottom;\\r\\n color: #707684;\\r\\n color: var(--grayText)\\r\\n }\\r\\n.ce-settings__button:not(:last-of-type){\\r\\n margin-right: 5px;\\r\\n }\\r\\n.ce-settings__button:hover {\\r\\n background-color: #eff2f5;\\r\\n background-color: var(--bg-light);\\r\\n }\\r\\n.ce-settings__button--active {\\r\\n color: #388AE5;\\r\\n color: var(--color-active-icon);\\r\\n }\\r\\n.ce-settings__button--delete {\\r\\n transition: background-color 300ms ease;\\r\\n will-change: background-color;\\r\\n }\\r\\n.ce-settings__button--delete .icon {\\r\\n transition: transform 200ms ease-out;\\r\\n will-change: transform;\\r\\n }\\r\\n.ce-settings__button--confirm {\\r\\n background-color: #E24A4A;\\r\\n background-color: var(--color-confirm);\\r\\n color: #fff\\r\\n }\\r\\n.ce-settings__button--confirm:hover {\\r\\n background-color: rgb(213, 74, 74) !important;\\r\\n background-color: rgb(213, 74, 74) !important;\\r\\n }\\r\\n.ce-settings__button--confirm .icon {\\r\\n transform: rotate(90deg);\\r\\n }\\r\\n.ce-settings-move-up:hover {\\r\\n cursor: pointer;\\r\\n }\\r\\n.ce-settings-move-up--disabled {\\r\\n cursor: not-allowed !important;\\r\\n opacity: .3;\\r\\n }\\r\\n.ce-block:first-of-type {\\r\\n margin-top: 0;\\r\\n }\\r\\n.ce-block--selected {\\r\\n background-image: linear-gradient(17deg, rgba(243, 248, 255, 0.03) 63.45%, rgba(207, 214, 229, 0.27) 98%);\\r\\n border-radius: 3px;\\r\\n }\\r\\n.ce-block__content {\\r\\n max-width: 650px;\\r\\n max-width: var(--content-width);\\r\\n margin: 0 auto;\\r\\n }\\r\\n\", \"\"]);\n\n// exports\n"],"sourceRoot":""} \ No newline at end of file diff --git a/example/plugins/code/code.js b/example/plugins/code/code.js index aaeb72b3..d3fe0112 100644 --- a/example/plugins/code/code.js +++ b/example/plugins/code/code.js @@ -3,25 +3,23 @@ * Creates code tag and adds content to this tag */ -var code = (function(code_plugin) { +var code = (function (code_plugin) { + var baseClass = 'ce-code'; - var baseClass = "ce-code"; - - /** + /** * Make initial header block * @param {object} JSON with block data * @return {Element} element to append */ - var make_ = function (data) { + var make_ = function (data) { + var tag = codex.editor.draw.node('TEXTAREA', [ baseClass ], {}); - var tag = codex.editor.draw.node('TEXTAREA', [baseClass], {}); + if (data && data.text) { + tag.value = data.text; + } - if (data && data.text) { - tag.value = data.text; - } - - return tag; - }; + return tag; + }; /** * Escapes HTML chars @@ -29,54 +27,45 @@ var code = (function(code_plugin) { * @param {string} input * @return {string} — escaped string */ - var escapeHTML_ = function (input) { + var escapeHTML_ = function (input) { + var div = document.createElement('DIV'), + text = document.createTextNode(input); - var div = document.createElement('DIV'), - text = document.createTextNode(input); + div.appendChild(text); - div.appendChild(text); - - return div.innerHTML; - - }; + return div.innerHTML; + }; /** * Method to render HTML block from JSON */ - code_plugin.render = function (data) { + code_plugin.render = function (data) { + return make_(data); + }; - return make_(data); - }; - - /** + /** * Method to extract JSON data from HTML block */ - code_plugin.save = function (blockContent) { - - var escaped = escapeHTML_(blockContent.value), - data = { - text : escaped - }; + code_plugin.save = function (blockContent) { + var escaped = escapeHTML_(blockContent.value), + data = { + text : escaped + }; - return data; + return data; + }; - }; + code_plugin.validate = function (data) { + if (data.text.trim() == '') + return; - code_plugin.validate = function (data) { + return true; + }; - if (data.text.trim() == '') - return; - - return true; - }; - - code_plugin.destroy = function () { - - code = null; - - }; - - return code_plugin; + code_plugin.destroy = function () { + code = null; + }; + return code_plugin; })({}); diff --git a/example/plugins/embed/embed.js b/example/plugins/embed/embed.js index 744ec85c..d727a623 100644 --- a/example/plugins/embed/embed.js +++ b/example/plugins/embed/embed.js @@ -2,210 +2,198 @@ * Embed plugin by gohabereg * @version 1.0.0 */ -var embed = function(embed_plugin){ +var embed = function (embed_plugin) { + var methods = { - var methods = { + addInternal: function (content) { + codex.editor.content.switchBlock(codex.editor.content.currentNode, content); - addInternal: function (content) { - codex.editor.content.switchBlock(codex.editor.content.currentNode, content); + var blockContent = codex.editor.content.currentNode.childNodes[0]; - var blockContent = codex.editor.content.currentNode.childNodes[0]; - blockContent.classList.add('embed__loader'); + blockContent.classList.add('embed__loader'); - setTimeout(function(){ - blockContent.classList.remove('embed__loader'); - }, 1000); + setTimeout(function () { + blockContent.classList.remove('embed__loader'); + }, 1000); + }, - }, + getHtmlWithEmbedId: function (type, id) { + return services[type].html.replace(/<\%\= remote\_id \%\>/g, id); + }, - getHtmlWithEmbedId: function (type, id) { - return services[type].html.replace(/<\%\= remote\_id \%\>/g, id); - }, + makeElementFromHtml: function (html) { + var wrapper = document.createElement('DIV'); - makeElementFromHtml: function(html) { - var wrapper = document.createElement('DIV'); + wrapper.innerHTML = html; - wrapper.innerHTML = html; + return wrapper; + }, - return wrapper; - }, + getRemoteId: function (source, execArray) { + switch(source) { + case 'yandex-music-track': + id = execArray[2]+'/'+execArray[1]; + break; + case 'yandex-music-playlist': + id = execArray[1]+'/'+execArray[2]; + break; + default: + id = execArray[1]; + } - getRemoteId: function(source, execArray) { + return id; + } + }; - switch(source) { - case 'yandex-music-track': - id = execArray[2]+'/'+execArray[1]; - break; - case 'yandex-music-playlist': - id = execArray[1]+'/'+execArray[2]; - break; - default: - id = execArray[1]; - } - - return id; - } - }; - - var services = { - youtube: { - regex: /^.*(?:(?:youtu\.be\/)|(?:youtube\.com)\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*)(?:[\?\&]t\=(\d*)|)/, - html: "", - height: 320, - width: 580 - } - }; + var services = { + youtube: { + regex: /^.*(?:(?:youtu\.be\/)|(?:youtube\.com)\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*)(?:[\?\&]t\=(\d*)|)/, + html: '', + height: 320, + width: 580 + } + }; - embed_plugin.make = function(data, isInternal) { + embed_plugin.make = function (data, isInternal) { + if (!data.remote_id) + return; - if (!data.remote_id) - return; + var html = methods.getHtmlWithEmbedId(data.source, data.remote_id), + block = methods.makeElementFromHtml(html); - var html = methods.getHtmlWithEmbedId(data.source, data.remote_id), - block = methods.makeElementFromHtml(html); + block.dataset.remoteId = data.remote_id; + block.dataset.source = data.source; + block.dataset.thumbnailUrl = data.thumbnailUrl; - block.dataset.remoteId = data.remote_id; - block.dataset.source = data.source; - block.dataset.thumbnailUrl = data.thumbnailUrl; + block.classList.add('embed'); - block.classList.add('embed'); + // var sidePadding = (600 - services[data.source].width) / 2 + 'px'; - // var sidePadding = (600 - services[data.source].width) / 2 + 'px'; + // block.style.padding = '30px ' + sidePadding; - // block.style.padding = '30px ' + sidePadding; + if (isInternal) { + methods.addInternal(block); + } - if (isInternal) { - methods.addInternal(block); - } + return block; + }; - return block; - - }; - - /** + /** * Saving JSON output. * Upload data via ajax */ - embed_plugin.save = function(blockContent) { + embed_plugin.save = function (blockContent) { + if (!blockContent) + return; - if (!blockContent) - return; - - var data, - source = blockContent.dataset.source; - - data = { - source: source, - remote_id: blockContent.dataset.remoteId, - thumbnailUrl: blockContent.dataset.thumbnailUrl, - height: services[source].height, - width: services[source].width - }; - - return data; + var data, + source = blockContent.dataset.source; + data = { + source: source, + remote_id: blockContent.dataset.remoteId, + thumbnailUrl: blockContent.dataset.thumbnailUrl, + height: services[source].height, + width: services[source].width }; - /** + return data; + }; + + /** * Render data */ - embed_plugin.render = function(data) { - return embed_plugin.make(data); + embed_plugin.render = function (data) { + return embed_plugin.make(data); + }; + + embed_plugin.urlPastedCallback = function (url, pattern) { + var execArray = pattern.regex.exec(url), + id = methods.getRemoteId(pattern.type, execArray); + + var data = { + source: pattern.type, + remote_id: id, + thumbnailUrl: url }; - embed_plugin.urlPastedCallback = function(url, pattern) { + embed_plugin.make(data, true); + }; - var execArray = pattern.regex.exec(url), - id = methods.getRemoteId(pattern.type, execArray); + embed_plugin.validate = function (savedData) { + var source = savedData.source, + execArray = services[source].regex.exec(savedData.thumbnailUrl), + remoteId = methods.getRemoteId(source, execArray); - var data = { - source: pattern.type, - remote_id: id, - thumbnailUrl: url - }; + return remoteId == savedData.remote_id; + }; - embed_plugin.make(data, true); - }; + embed_plugin.pastePatterns = [ + { + type: 'vk', + regex: /https?:\/\/vk\.com\/.*(?:video)([-0-9]+_[0-9]+)/, // /https?.+vk?.com\/feed\?w=wall\d+_\d+/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'youtube', + regex: /(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'vimeo', + regex: /(?:http[s]?:\/\/)?(?:www.)?vimeo\.co(?:.+\/([^\/]\d+)(?:#t=[\d]+)?s?$)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'coub', + regex: /https?:\/\/coub\.com\/view\/([^\/\?\&]+)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'vine', + regex: /https?:\/\/vine\.co\/v\/([^\/\?\&]+)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'imgur', + regex: /https?:\/\/(?:i\.)?imgur\.com.*\/([a-zA-Z0-9]+)(?:\.gifv)?/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'gfycat', + regex: /https?:\/\/gfycat\.com(?:\/detail)?\/([a-zA-Z]+)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'twitch-channel', + regex: /https?:\/\/www.twitch.tv\/([^\/\?\&]*)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'twitch-video', + regex: /https?:\/\/www.twitch.tv\/(?:[^\/\?\&]*\/v|videos)\/([0-9]*)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'yandex-music-album', + regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'yandex-music-track', + regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)\/track\/([0-9]*)/, + callback: embed_plugin.urlPastedCallback + }, + { + type: 'yandex-music-playlist', + regex: /https?:\/\/music.yandex.ru\/users\/([^\/\?\&]*)\/playlists\/([0-9]*)/, + callback: embed_plugin.urlPastedCallback + } ]; - embed_plugin.validate = function(savedData) { - - var source = savedData.source, - execArray = services[source].regex.exec(savedData.thumbnailUrl), - remoteId = methods.getRemoteId(source, execArray); - - return remoteId == savedData.remote_id; - - }; - - embed_plugin.pastePatterns = [ - { - type: 'vk', - regex: /https?:\/\/vk\.com\/.*(?:video)([-0-9]+_[0-9]+)/, ///https?.+vk?.com\/feed\?w=wall\d+_\d+/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'youtube', - regex: /(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)([^\s&]+)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'vimeo', - regex: /(?:http[s]?:\/\/)?(?:www.)?vimeo\.co(?:.+\/([^\/]\d+)(?:#t=[\d]+)?s?$)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'coub', - regex: /https?:\/\/coub\.com\/view\/([^\/\?\&]+)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'vine', - regex: /https?:\/\/vine\.co\/v\/([^\/\?\&]+)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'imgur', - regex: /https?:\/\/(?:i\.)?imgur\.com.*\/([a-zA-Z0-9]+)(?:\.gifv)?/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'gfycat', - regex: /https?:\/\/gfycat\.com(?:\/detail)?\/([a-zA-Z]+)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'twitch-channel', - regex: /https?:\/\/www.twitch.tv\/([^\/\?\&]*)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'twitch-video', - regex: /https?:\/\/www.twitch.tv\/(?:[^\/\?\&]*\/v|videos)\/([0-9]*)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'yandex-music-album', - regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'yandex-music-track', - regex: /https?:\/\/music.yandex.ru\/album\/([0-9]*)\/track\/([0-9]*)/, - callback: embed_plugin.urlPastedCallback - }, - { - type: 'yandex-music-playlist', - regex: /https?:\/\/music.yandex.ru\/users\/([^\/\?\&]*)\/playlists\/([0-9]*)/, - callback: embed_plugin.urlPastedCallback - } ]; - - embed_plugin.destroy = function () { - - embed = null; - - }; - - return embed_plugin; + embed_plugin.destroy = function () { + embed = null; + }; + return embed_plugin; }({}); \ No newline at end of file diff --git a/example/plugins/header/header.js b/example/plugins/header/header.js index 6e73ee88..42dfc00a 100644 --- a/example/plugins/header/header.js +++ b/example/plugins/header/header.js @@ -3,49 +3,44 @@ * H e a d e r */ -var header = (function(header_plugin) { - - /** +var header = (function (header_plugin) { + /** * @private */ - var methods_ = { + var methods_ = { - /** + /** * Binds click event to passed button */ - addSelectTypeClickListener : function (el, type) { + addSelectTypeClickListener : function (el, type) { + el.addEventListener('click', function () { + methods_.selectTypeClicked(type); + }, false); + }, - el.addEventListener('click', function () { - - methods_.selectTypeClicked(type); - - }, false); - }, - - /** + /** * Replaces old header with new type * @params {string} type - new header tagName: H1—H6 */ - selectTypeClicked : function (type) { + selectTypeClicked : function (type) { + var old_header, new_header; - var old_header, new_header; + /** Now current header stored as a currentNode */ + old_header = codex.editor.content.currentNode.querySelector('[contentEditable]'); - /** Now current header stored as a currentNode */ - old_header = codex.editor.content.currentNode.querySelector('[contentEditable]'); + /** Making new header */ + new_header = codex.editor.draw.node(type, [ 'ce-header' ], { innerHTML : old_header.innerHTML }); + new_header.contentEditable = true; + new_header.setAttribute('data-placeholder', 'Заголовок'); + new_header.dataset.headerData = type; - /** Making new header */ - new_header = codex.editor.draw.node(type, ['ce-header'], { innerHTML : old_header.innerHTML }); - new_header.contentEditable = true; - new_header.setAttribute('data-placeholder', 'Заголовок'); - new_header.dataset.headerData = type; + codex.editor.content.switchBlock(old_header, new_header, 'header'); - codex.editor.content.switchBlock(old_header, new_header, 'header'); + /** Close settings after replacing */ + codex.editor.toolbar.settings.close(); + } - /** Close settings after replacing */ - codex.editor.toolbar.settings.close(); - } - - }; + }; /** * @private @@ -54,116 +49,102 @@ var header = (function(header_plugin) { * @param {object} JSON with block data * @return {Element} element to append */ - var make_ = function (data) { - - var availableTypes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], - tag, - headerType = 'h2'; + var make_ = function (data) { + var availableTypes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], + tag, + headerType = 'h2'; - if ( data && data['heading-styles'] && availableTypes.includes(data['heading-styles']) ) { + if ( data && data['heading-styles'] && availableTypes.includes(data['heading-styles']) ) { + headerType = data['heading-styles']; + } - headerType = data['heading-styles']; + tag = document.createElement(headerType); - } - - tag = document.createElement(headerType); - - /** + /** * Save header type in data-attr. * We need it in save method to extract type from HTML to JSON */ - tag.dataset.headerData = headerType; + tag.dataset.headerData = headerType; - if (data && data.text) { - tag.textContent = data.text; - } + if (data && data.text) { + tag.textContent = data.text; + } - if (!tag.dataset.headerData) { - tag.dataset.headerData = 'h2'; - } + if (!tag.dataset.headerData) { + tag.dataset.headerData = 'h2'; + } - tag.classList.add('ce-header'); - tag.setAttribute('data-placeholder', 'Заголовок'); - tag.contentEditable = true; + tag.classList.add('ce-header'); + tag.setAttribute('data-placeholder', 'Заголовок'); + tag.contentEditable = true; - return tag; + return tag; + }; - }; + header_plugin.prepareDataForSave = function (data) { - header_plugin.prepareDataForSave = function(data) { + }; - }; - - /** + /** * Method to render HTML block from JSON */ - header_plugin.render = function (data) { + header_plugin.render = function (data) { + return make_(data); + }; - return make_(data); - - }; - - /** + /** * Method to extract JSON data from HTML block */ - header_plugin.save = function (blockContent) { - - var data = { - "heading-styles": blockContent.dataset.headerData, - "format": "html", - "text": blockContent.textContent || '' - }; - - return data; + header_plugin.save = function (blockContent) { + var data = { + 'heading-styles': blockContent.dataset.headerData, + 'format': 'html', + 'text': blockContent.textContent || '' }; - /** + return data; + }; + + /** * Settings panel content * - - - - - - - - - - - - - * | настройки H1 H2 H3 | * - - - - - - - - - - - - - * @return {Element} element contains all settings */ - header_plugin.makeSettings = function () { - - var holder = codex.editor.draw.node('DIV', ['cdx-plugin-settings--horisontal'], {} ), - types = { - h2: 'H2', - h3: 'H3', - h4: 'H4' - }, - selectTypeButton; - - /** Now add type selectors */ - for (var type in types){ - - selectTypeButton = codex.editor.draw.node('SPAN', ['cdx-plugin-settings__item'], { textContent : types[type] }); - methods_.addSelectTypeClickListener(selectTypeButton, type); - holder.appendChild(selectTypeButton); - - } - - return holder; - }; - - header_plugin.validate = function(data) { - - if (data.text.trim() === '' || data['heading-styles'].trim() === ''){ - return false; - } - - return true; - }; - - header_plugin.destroy = function () { - - header = null; + header_plugin.makeSettings = function () { + var holder = codex.editor.draw.node('DIV', [ 'cdx-plugin-settings--horisontal' ], {} ), + types = { + h2: 'H2', + h3: 'H3', + h4: 'H4' + }, + selectTypeButton; + /** Now add type selectors */ + for (var type in types) { + selectTypeButton = codex.editor.draw.node('SPAN', [ 'cdx-plugin-settings__item' ], { textContent : types[type] }); + methods_.addSelectTypeClickListener(selectTypeButton, type); + holder.appendChild(selectTypeButton); } - return header_plugin; + return holder; + }; + header_plugin.validate = function (data) { + if (data.text.trim() === '' || data['heading-styles'].trim() === '') { + return false; + } + + return true; + }; + + header_plugin.destroy = function () { + header = null; + }; + + return header_plugin; })({}); diff --git a/example/plugins/image/image.js b/example/plugins/image/image.js index b0b83746..85889122 100644 --- a/example/plugins/image/image.js +++ b/example/plugins/image/image.js @@ -4,34 +4,33 @@ * * @version 1.3.0 */ -var image = (function(image_plugin) { - - /** +var image = (function (image_plugin) { + /** * @private * * CSS classNames */ - var elementClasses_ = { + var elementClasses_ = { - ce_image : 'ce-image', - loading : 'ce-plugin-image__loader', - blockStretched: 'ce-block--stretched', - uploadedImage : { - centered : 'ce-plugin-image__uploaded--centered', - stretched : 'ce-plugin-image__uploaded--stretched' - }, - imageCaption : 'ce-plugin-image__caption', - imageWrapper : 'ce-plugin-image__wrapper', - formHolder : 'ce-plugin-image__holder', - uploadButton : 'ce-plugin-image__button', - imagePreview : 'ce-image__preview', - selectorHolder: 'ce-settings-checkbox', - selectorButton: 'ce-settings-checkbox__toggler', - settingsItem: 'ce-image-settings__item', - imageWrapperBordered : 'ce-image__wrapper--bordered', - toggled : 'ce-image-settings__item--toggled' + ce_image : 'ce-image', + loading : 'ce-plugin-image__loader', + blockStretched: 'ce-block--stretched', + uploadedImage : { + centered : 'ce-plugin-image__uploaded--centered', + stretched : 'ce-plugin-image__uploaded--stretched' + }, + imageCaption : 'ce-plugin-image__caption', + imageWrapper : 'ce-plugin-image__wrapper', + formHolder : 'ce-plugin-image__holder', + uploadButton : 'ce-plugin-image__button', + imagePreview : 'ce-image__preview', + selectorHolder: 'ce-settings-checkbox', + selectorButton: 'ce-settings-checkbox__toggler', + settingsItem: 'ce-image-settings__item', + imageWrapperBordered : 'ce-image__wrapper--bordered', + toggled : 'ce-image-settings__item--toggled' - }; + }; /** * @@ -39,467 +38,434 @@ var image = (function(image_plugin) { * * UI methods */ - var ui_ = { + var ui_ = { - holder : function(){ + holder : function () { + var element = document.createElement('DIV'); - var element = document.createElement('DIV'); + element.classList.add(elementClasses_.formHolder); + element.classList.add(elementClasses_.ce_image); - element.classList.add(elementClasses_.formHolder); - element.classList.add(elementClasses_.ce_image); + return element; + }, - return element; - }, + uploadButton : function () { + var button = document.createElement('SPAN'); - uploadButton : function(){ + button.classList.add(elementClasses_.uploadButton); - var button = document.createElement('SPAN'); + button.innerHTML = ' '; + button.innerHTML += 'Загрузить фотографию'; - button.classList.add(elementClasses_.uploadButton); + return button; + }, - button.innerHTML = ' '; - button.innerHTML += 'Загрузить фотографию'; - - return button; - - }, - - /** + /** * @param {object} file - file path * @param {string} style - css class * @return {object} image - document IMG tag */ - image : function(file, styles) { + image : function (file, styles) { + var image = document.createElement('IMG'); - var image = document.createElement('IMG'); + styles.map(function (item) { + image.classList.add(item); + }); - styles.map(function(item) { - image.classList.add(item); - }); + image.src = file.url; + image.dataset.bigUrl = file.bigUrl; - image.src = file.url; - image.dataset.bigUrl = file.bigUrl; + return image; + }, - return image; - }, + wrapper : function () { + var div = document.createElement('div'); - wrapper : function() { + div.classList.add(elementClasses_.imageWrapper); - var div = document.createElement('div'); + return div; + }, - div.classList.add(elementClasses_.imageWrapper); + caption : function () { + var div = document.createElement('div'); - return div; - }, + div.classList.add(elementClasses_.imageCaption); + div.contentEditable = true; - caption : function() { - - var div = document.createElement('div'); - - div.classList.add(elementClasses_.imageCaption); - div.contentEditable = true; - - return div; - }, - /** + return div; + }, + /** * Draws form for image upload */ - makeForm : function() { + makeForm : function () { + var holder = ui_.holder(), + uploadButton = ui_.uploadButton(); - var holder = ui_.holder(), - uploadButton = ui_.uploadButton(); + holder.appendChild(uploadButton); - holder.appendChild(uploadButton); + uploadButton.addEventListener('click', uploadButtonClicked_, false ); - uploadButton.addEventListener('click', uploadButtonClicked_, false ); + image.holder = holder; - image.holder = holder; - - return holder; - }, + return holder; + }, - /** + /** * wraps image and caption * @param {object} data - image information * @param {string} imageTypeClass - plugin's style * @param {boolean} stretched - stretched or not * @return wrapped block with image and caption */ - makeImage : function(data, imageTypeClasses, stretched, bordered) { + makeImage : function (data, imageTypeClasses, stretched, bordered) { + var file = data, + text = data.caption, + type = data.type, + image = ui_.image(file, imageTypeClasses), + caption = ui_.caption(), + wrapper = ui_.wrapper(); - var file = data, - text = data.caption, - type = data.type, - image = ui_.image(file, imageTypeClasses), - caption = ui_.caption(), - wrapper = ui_.wrapper(); + caption.innerHTML = text || ''; - caption.innerHTML = text || ''; + wrapper.dataset.stretched = stretched; + wrapper.dataset.bordered = bordered; - wrapper.dataset.stretched = stretched; - wrapper.dataset.bordered = bordered; + /** Appeding to the wrapper */ + wrapper.appendChild(image); + wrapper.appendChild(caption); - /** Appeding to the wrapper */ - wrapper.appendChild(image); - wrapper.appendChild(caption); + return wrapper; + }, - return wrapper; - }, - - /** + /** * @param {HTML} data - Rendered block with image */ - getImage : function(data) { - - var image = data.querySelector('.' + elementClasses_.uploadedImage.centered) || + getImage : function (data) { + var image = data.querySelector('.' + elementClasses_.uploadedImage.centered) || data.querySelector('.' + elementClasses_.uploadedImage.stretched); - return image; - }, + return image; + }, - /** + /** * wraps image and caption * @deprecated * @param {object} data - image information * @return wrapped block with image and caption */ - centeredImage : function(data) { + centeredImage : function (data) { + var file = data.file, + text = data.caption, + type = data.type, + image = ui_.image(file, elementClasses_.uploadedImage.centered), + caption = ui_.caption(), + wrapper = ui_.wrapper(); - var file = data.file, - text = data.caption, - type = data.type, - image = ui_.image(file, elementClasses_.uploadedImage.centered), - caption = ui_.caption(), - wrapper = ui_.wrapper(); + caption.textContent = text; - caption.textContent = text; + wrapper.dataset.stretched = 'false'; - wrapper.dataset.stretched = 'false'; + /** Appeding to the wrapper */ + wrapper.appendChild(image); + wrapper.appendChild(caption); - /** Appeding to the wrapper */ - wrapper.appendChild(image); - wrapper.appendChild(caption); + return wrapper; + }, - return wrapper; - }, - - /** + /** * wraps image and caption * @deprecated * @param {object} data - image information * @return stretched image */ - stretchedImage : function(data) { + stretchedImage : function (data) { + var file = data.file, + text = data.caption, + type = data.type, + image = ui_.image(file, elementClasses_.uploadedImage.stretched), + caption = ui_.caption(), + wrapper = ui_.wrapper(); - var file = data.file, - text = data.caption, - type = data.type, - image = ui_.image(file, elementClasses_.uploadedImage.stretched), - caption = ui_.caption(), - wrapper = ui_.wrapper(); + caption.textContent = text; - caption.textContent = text; + wrapper.dataset.stretched = 'true'; - wrapper.dataset.stretched = 'true'; + /** Appeding to the wrapper */ + wrapper.appendChild(image); + wrapper.appendChild(caption); - /** Appeding to the wrapper */ - wrapper.appendChild(image); - wrapper.appendChild(caption); + return wrapper; + } - return wrapper; - - } - - }; + }; /** * @private * * After render callback */ - var uploadButtonClicked_ = function(event) { + var uploadButtonClicked_ = function (event) { + var url = image_plugin.config.uploadImage, + beforeSend = uploadingCallbacks_.ByClick.beforeSend, + success = uploadingCallbacks_.ByClick.success, + error = uploadingCallbacks_.ByClick.error; - var url = image_plugin.config.uploadImage, - beforeSend = uploadingCallbacks_.ByClick.beforeSend, - success = uploadingCallbacks_.ByClick.success, - error = uploadingCallbacks_.ByClick.error; + /** Define callbacks */ + codex.editor.transport.selectAndUpload({ + url : url, + multiple : false, + accept : 'image/*', + beforeSend : beforeSend, + success : success, + error : error + }); + }; - /** Define callbacks */ - codex.editor.transport.selectAndUpload({ - url : url, - multiple : false, - accept : 'image/*', - beforeSend : beforeSend, - success : success, - error : error - }); - }; + var methods_ = { - var methods_ = { + addSelectTypeClickListener : function (el, type) { + el.addEventListener('click', function () { + // el - settings element - addSelectTypeClickListener : function(el, type) { + switch (type) { + case 'bordered': + methods_.toggleBordered(type, this); break; + case 'stretched': + methods_.toggleStretched(type, this); break; + } + }, false); + }, - el.addEventListener('click', function() { + toggleBordered : function (type, clickedSettingsItem ) { + var current = codex.editor.content.currentNode, + blockContent = current.childNodes[0], + img = ui_.getImage(current), + wrapper = current.querySelector('.' + elementClasses_.imageWrapper); - // el - settings element + if (!img) { + return; + } - switch (type) { - case 'bordered': - methods_.toggleBordered(type, this); break; - case 'stretched': - methods_.toggleStretched(type, this); break; - } - - - }, false); - - }, - - toggleBordered : function(type, clickedSettingsItem ) { - - var current = codex.editor.content.currentNode, - blockContent = current.childNodes[0], - img = ui_.getImage(current), - wrapper = current.querySelector('.' + elementClasses_.imageWrapper); - - if (!img) { - return; - } - - /** + /** * Add classes to the IMG tag and to the Settings element */ - img.classList.toggle(elementClasses_.imageWrapperBordered); - clickedSettingsItem.classList.toggle(elementClasses_.toggled); + img.classList.toggle(elementClasses_.imageWrapperBordered); + clickedSettingsItem.classList.toggle(elementClasses_.toggled); - /** + /** * Save settings in dataset */ - wrapper.dataset.bordered = img.classList.contains(elementClasses_.imageWrapperBordered); + wrapper.dataset.bordered = img.classList.contains(elementClasses_.imageWrapperBordered); - setTimeout(function() { - codex.editor.toolbar.settings.close(); - }, 200); + setTimeout(function () { + codex.editor.toolbar.settings.close(); + }, 200); + }, - }, + toggleStretched : function ( type, clickedSettingsItem ) { + var current = codex.editor.content.currentNode, + blockContent = current.childNodes[0], + img = ui_.getImage(current), + wrapper = current.querySelector('.' + elementClasses_.imageWrapper); - toggleStretched : function( type, clickedSettingsItem ) { + if (!img) { + return; + } - var current = codex.editor.content.currentNode, - blockContent = current.childNodes[0], - img = ui_.getImage(current), - wrapper = current.querySelector('.' + elementClasses_.imageWrapper); + /** Clear classList */ + blockContent.classList.add(elementClasses_.blockStretched); + img.classList.toggle(elementClasses_.uploadedImage.stretched); + img.classList.toggle(elementClasses_.uploadedImage.centered); - if (!img) { - return; - } + clickedSettingsItem.classList.toggle(elementClasses_.toggled); - /** Clear classList */ - blockContent.classList.add(elementClasses_.blockStretched); - img.classList.toggle(elementClasses_.uploadedImage.stretched); - img.classList.toggle(elementClasses_.uploadedImage.centered); + wrapper.dataset.stretched = img.classList.contains(elementClasses_.uploadedImage.stretched); - clickedSettingsItem.classList.toggle(elementClasses_.toggled); - - wrapper.dataset.stretched = img.classList.contains(elementClasses_.uploadedImage.stretched); - - setTimeout(function() { - codex.editor.toolbar.settings.close(); - }, 1000); - - } - }; + setTimeout(function () { + codex.editor.toolbar.settings.close(); + }, 1000); + } + }; /** * @private * Callbacks */ - var uploadingCallbacks_ = { + var uploadingCallbacks_ = { - ByClick : { + ByClick : { - /** + /** * Before sending ajax request */ - beforeSend : function() { + beforeSend : function () { + var input = codex.editor.transport.input, + files = input.files; - var input = codex.editor.transport.input, - files = input.files; + var validFileExtensions = ['jpg', 'jpeg', 'bmp', 'gif', 'png']; - var validFileExtensions = ["jpg", "jpeg", "bmp", "gif", "png"]; + var type = files[0].type.split('/'); - var type = files[0].type.split('/'); + var result = validFileExtensions.some(function (ext) { + return ext == type[1]; + }); - var result = validFileExtensions.some(function(ext) { - return ext == type[1]; - }); + if (!result) { + return; + } - if (!result) { - return; - } + var reader = new FileReader(); - var reader = new FileReader(); - reader.readAsDataURL(files[0]); + reader.readAsDataURL(files[0]); - reader.onload = function(e) { + reader.onload = function (e) { + var data = { + background : false, + border : false, + isstretch : false, + url : e.target.result, + bigUrl : null, + width : null, + height : null, + additionalData : null, + caption : '', + cover : null + }; - var data = { - background : false, - border : false, - isstretch : false, - url : e.target.result, - bigUrl : null, - width : null, - height : null, - additionalData : null, - caption : '', - cover : null - }; + var newImage = make_(data); - var newImage = make_(data); + codex.editor.content.switchBlock(image.holder, newImage, 'image'); + newImage.classList.add(elementClasses_.imagePreview); - codex.editor.content.switchBlock(image.holder, newImage, 'image'); - newImage.classList.add(elementClasses_.imagePreview); - - /** + /** * Change holder to image */ - image.holder = newImage; - }; + image.holder = newImage; + }; + }, - }, + /** Photo was uploaded successfully */ + success : function (result) { + var parsed = JSON.parse(result), + data, + currentBlock = codex.editor.content.currentNode; - /** Photo was uploaded successfully */ - success : function(result) { - - var parsed = JSON.parse(result), - data, - currentBlock = codex.editor.content.currentNode; - - /** + /** * Preparing {Object} data to draw an image * @uses ceImage.make method */ - data = parsed.data; + data = parsed.data; - image.holder.classList.remove(elementClasses_.imagePreview); + image.holder.classList.remove(elementClasses_.imagePreview); - /** + /** * Change src of image */ - var newImage = image.holder.getElementsByTagName('IMG')[0]; + var newImage = image.holder.getElementsByTagName('IMG')[0]; - newImage.src = parsed.data.url; - newImage.dataset.bigUrl = parsed.data.bigUrl; - newImage.dataset.width = parsed.data.width; - newImage.dataset.height = parsed.data.height; - newImage.dataset.additionalData = parsed.data.additionalData; + newImage.src = parsed.data.url; + newImage.dataset.bigUrl = parsed.data.bigUrl; + newImage.dataset.width = parsed.data.width; + newImage.dataset.height = parsed.data.height; + newImage.dataset.additionalData = parsed.data.additionalData; + }, - }, + /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */ + error : function (result) { + var oldHolder = image.holder; + var form = ui_.makeForm(); - /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */ - error : function(result) { + codex.editor.content.switchBlock(oldHolder, form, 'image'); + } + }, - var oldHolder = image.holder; - var form = ui_.makeForm(); + ByPaste : { - codex.editor.content.switchBlock(oldHolder, form, 'image'); - - } - }, - - ByPaste : { - - /** + /** * Direct upload * Any URL that contains image extension * @param url */ - uploadImageFromUrl : function(path) { + uploadImageFromUrl : function (path) { + var image, + current = codex.editor.content.currentNode, + beforeSend, + success_callback; - var image, - current = codex.editor.content.currentNode, - beforeSend, - success_callback; + /** When image is uploaded to redactors folder */ + success_callback = function (data) { + var imageInfo = JSON.parse(data); - /** When image is uploaded to redactors folder */ - success_callback = function(data) { + var newImage = image.getElementsByTagName('IMG')[0]; - var imageInfo = JSON.parse(data); + newImage.dataset.stretched = false; + newImage.dataset.src = imageInfo.url; + newImage.dataset.bigUrl = imageInfo.bigUrl; + newImage.dataset.width = imageInfo.width; + newImage.dataset.height = imageInfo.height; + newImage.dataset.additionalData = imageInfo.additionalData; - var newImage = image.getElementsByTagName('IMG')[0]; + image.classList.remove(elementClasses_.imagePreview); + }; - newImage.dataset.stretched = false; - newImage.dataset.src = imageInfo.url; - newImage.dataset.bigUrl = imageInfo.bigUrl; - newImage.dataset.width = imageInfo.width; - newImage.dataset.height = imageInfo.height; - newImage.dataset.additionalData = imageInfo.additionalData; + /** Before sending XMLHTTP request */ + beforeSend = function () { + var content = current.querySelector('.ce-block__content'); - image.classList.remove(elementClasses_.imagePreview); + var data = { + background: false, + border: false, + isStretch: false, + file: { + url: path, + bigUrl: null, + width: null, + height: null, + additionalData: null + }, + caption: '', + cover: null + }; - }; + image = codex.editor.tools.image_extended.render(data); - /** Before sending XMLHTTP request */ - beforeSend = function() { + image.classList.add(elementClasses_.imagePreview); - var content = current.querySelector('.ce-block__content'); + var img = image.querySelector('img'); - var data = { - background: false, - border: false, - isStretch: false, - file: { - url: path, - bigUrl: null, - width: null, - height: null, - additionalData: null - }, - caption: '', - cover: null - }; + codex.editor.content.switchBlock(codex.editor.content.currentNode, image, 'image'); + }; - image = codex.editor.tools.image_extended.render(data); + /** Preparing data for XMLHTTP */ + var data = { + url: image_plugin.config.uploadFromUrl, + type: 'POST', + data : { + url: path + }, + beforeSend : beforeSend, + success : success_callback + }; - image.classList.add(elementClasses_.imagePreview); + codex.editor.core.ajax(data); + } - var img = image.querySelector('img'); - - codex.editor.content.switchBlock(codex.editor.content.currentNode, image, 'image'); - - }; - - /** Preparing data for XMLHTTP */ - var data = { - url: image_plugin.config.uploadFromUrl, - type: "POST", - data : { - url: path - }, - beforeSend : beforeSend, - success : success_callback - }; - - codex.editor.core.ajax(data); - } - - } - }; + } + }; /** * Image path * @type {null} */ - image_plugin.path = null; + image_plugin.path = null; - /** + /** * Plugin configuration */ - image_plugin.config = null; + image_plugin.config = null; - /** + /** * * @private * @@ -507,38 +473,30 @@ var image = (function(image_plugin) { * @return {*} * */ - var make_ = function ( data ) { + var make_ = function ( data ) { + var holder, + classes = []; - var holder, - classes = []; + if (data) { + if (data.border) { + classes.push(elementClasses_.imageWrapperBordered); + } - if (data) { + if ( data.isstretch || data.isstretch === 'true') { + classes.push(elementClasses_.uploadedImage.stretched); + holder = ui_.makeImage(data, classes, 'true', data.border); + } else { + classes.push(elementClasses_.uploadedImage.centered); + holder = ui_.makeImage(data, classes, 'false', data.border); + } - if (data.border) { - classes.push(elementClasses_.imageWrapperBordered); - } + return holder; + } else { + holder = ui_.makeForm(); - if ( data.isstretch || data.isstretch === 'true') { - - classes.push(elementClasses_.uploadedImage.stretched); - holder = ui_.makeImage(data, classes, 'true', data.border); - - } else { - - classes.push(elementClasses_.uploadedImage.centered); - holder = ui_.makeImage(data, classes, 'false', data.border); - - } - - return holder; - - } else { - - holder = ui_.makeForm(); - - return holder; - } - }; + return holder; + } + }; /** * @private @@ -547,155 +505,143 @@ var image = (function(image_plugin) { * * @param data */ - var prepareDataForSave_ = function(data) { + var prepareDataForSave_ = function (data) { - }; + }; /** * @public * @param config */ - image_plugin.prepare = function(config) { + image_plugin.prepare = function (config) { + image_plugin.config = config; - image_plugin.config = config; + return Promise.resolve(); + }; - return Promise.resolve(); - }; - - /** + /** * @public * * this tool works when tool is clicked in toolbox */ - image_plugin.appendCallback = function(event) { + image_plugin.appendCallback = function (event) { + /** Upload image and call success callback*/ + uploadButtonClicked_(event); + }; - /** Upload image and call success callback*/ - uploadButtonClicked_(event); - - }; - - /** + /** * @public * * @param data * @return {*} */ - image_plugin.render = function( data ) { + image_plugin.render = function ( data ) { + return make_(data); + }; - return make_(data); - }; - - /** + /** * @public * * @param block * @return {{background: boolean, border: boolean, isstretch: boolean, file: {url: (*|string|Object), bigUrl: (null|*), width: *, height: *, additionalData: null}, caption: (string|*|string), cover: null}} */ - image_plugin.save = function ( block ) { + image_plugin.save = function ( block ) { + var content = block, + image = ui_.getImage(content), + caption = content.querySelector('.' + elementClasses_.imageCaption); - var content = block, - image = ui_.getImage(content), - caption = content.querySelector('.' + elementClasses_.imageCaption); - - var data = { - background : false, - border : content.dataset.bordered === 'true' ? true : false, - isstretch : content.dataset.stretched === 'true' ? true : false, - // file : { - url : image.dataset.src || image.src, - bigUrl : image.dataset.bigUrl, - width : image.width, - height : image.height, - additionalData :null, - // }, - caption : caption.innerHTML || '', - cover : null - }; - - return data; + var data = { + background : false, + border : content.dataset.bordered === 'true' ? true : false, + isstretch : content.dataset.stretched === 'true' ? true : false, + // file : { + url : image.dataset.src || image.src, + bigUrl : image.dataset.bigUrl, + width : image.width, + height : image.height, + additionalData :null, + // }, + caption : caption.innerHTML || '', + cover : null }; - /** + return data; + }; + + /** * @public * * Settings panel content * @return {Element} element contains all settings */ - image_plugin.makeSettings = function () { + image_plugin.makeSettings = function () { + var currentNode = codex.editor.content.currentNode, + wrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper), + holder = document.createElement('DIV'), + types = { + stretched : 'На всю ширину', + bordered : 'Добавить рамку' + }, + currentImageWrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper ), + currentImageSettings = currentImageWrapper.dataset; - var currentNode = codex.editor.content.currentNode, - wrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper), - holder = document.createElement('DIV'), - types = { - stretched : "На всю ширину", - bordered : "Добавить рамку" - }, - currentImageWrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper ), - currentImageSettings = currentImageWrapper.dataset; + /** Add holder classname */ + holder.className = 'ce-image-settings'; - /** Add holder classname */ - holder.className = 'ce-image-settings'; - - /** Now add type selectors */ - for (var type in types){ - - /** + /** Now add type selectors */ + for (var type in types) { + /** * Settings template */ - var settingsItem = document.createElement('DIV'), - selectorsHolder = document.createElement('SPAN'), - selectorsButton = document.createElement('SPAN'); + var settingsItem = document.createElement('DIV'), + selectorsHolder = document.createElement('SPAN'), + selectorsButton = document.createElement('SPAN'); - settingsItem.classList.add(elementClasses_.settingsItem); - selectorsHolder.classList.add(elementClasses_.selectorHolder); - selectorsButton.classList.add(elementClasses_.selectorButton); + settingsItem.classList.add(elementClasses_.settingsItem); + selectorsHolder.classList.add(elementClasses_.selectorHolder); + selectorsButton.classList.add(elementClasses_.selectorButton); - selectorsHolder.appendChild(selectorsButton); - settingsItem.appendChild(selectorsHolder); + selectorsHolder.appendChild(selectorsButton); + settingsItem.appendChild(selectorsHolder); - selectTypeButton = document.createTextNode(types[type]); - settingsItem.appendChild(selectTypeButton); + selectTypeButton = document.createTextNode(types[type]); + settingsItem.appendChild(selectTypeButton); - /** + /** * Activate previously selected settings */ - if ( currentImageSettings[type] == 'true' ){ - settingsItem.classList.add(elementClasses_.toggled); - } + if ( currentImageSettings[type] == 'true' ) { + settingsItem.classList.add(elementClasses_.toggled); + } - methods_.addSelectTypeClickListener(settingsItem, type); + methods_.addSelectTypeClickListener(settingsItem, type); - holder.appendChild(settingsItem); + holder.appendChild(settingsItem); + } - } + return holder; + }; - return holder; - - }; - - /** + /** * Share as API */ - image_plugin.uploadImageFromUri = uploadingCallbacks_.ByPaste.uploadImageFromUrl; + image_plugin.uploadImageFromUri = uploadingCallbacks_.ByPaste.uploadImageFromUrl; - image_plugin.pastePatterns = [ - { - type: 'image', - regex: /(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*\.(?:jpe?g|gif|png))(?:\?([^#]*))?(?:#(.*))?/i, - callback: image_plugin.uploadImageFromUri - }, - { - type: 'uploadCare', - regex: /^https:\/\/(uploadcare\.cmtt\.ru|ucarecdn\.com|static[0-9]+\.siliconrus\.cmtt\.ru|static[0-9]+\.cmtt\.ru)/i, - callback: image_plugin.uploadImageFromUri - } ]; + image_plugin.pastePatterns = [ + { + type: 'image', + regex: /(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*\.(?:jpe?g|gif|png))(?:\?([^#]*))?(?:#(.*))?/i, + callback: image_plugin.uploadImageFromUri + }, + { + type: 'uploadCare', + regex: /^https:\/\/(uploadcare\.cmtt\.ru|ucarecdn\.com|static[0-9]+\.siliconrus\.cmtt\.ru|static[0-9]+\.cmtt\.ru)/i, + callback: image_plugin.uploadImageFromUri + } ]; - image_plugin.destroy = function () { - - image = null; - - }; - - return image_plugin; + image_plugin.destroy = function () { + image = null; + }; + return image_plugin; })({}); \ No newline at end of file diff --git a/example/plugins/instagram/instagram.js b/example/plugins/instagram/instagram.js index 9072ef2d..093f0220 100644 --- a/example/plugins/instagram/instagram.js +++ b/example/plugins/instagram/instagram.js @@ -2,161 +2,142 @@ * Instagram plugin * @version 1.0.0 */ -var instagram = (function(instagram_plugin) { +var instagram = (function (instagram_plugin) { + var methods = { - var methods = { + render : function (content) { + codex.editor.content.switchBlock(codex.editor.content.currentNode, content); - render : function(content) { + setTimeout(function () { + window.instgrm.Embeds.process(); + }, 200); + }, - codex.editor.content.switchBlock(codex.editor.content.currentNode, content); - - setTimeout(function() { - window.instgrm.Embeds.process(); - }, 200); - - }, - - /** + /** * Drawing html content. * * @param url * @returns {Element} blockquote - HTML template for Instagram Embed JS */ - instagramBlock : function(url) { + instagramBlock : function (url) { + var blockquote = codex.editor.draw.node('BLOCKQUOTE', 'instagram-media instagram', {}), + div = codex.editor.draw.node('DIV', '', {}), + paragraph = codex.editor.draw.node('P', 'ce-paste__instagram--p', {}), + anchor = codex.editor.draw.node('A', '', { href : url }); - var blockquote = codex.editor.draw.node('BLOCKQUOTE', 'instagram-media instagram', {}), - div = codex.editor.draw.node('DIV', '', {}), - paragraph = codex.editor.draw.node('P', 'ce-paste__instagram--p', {}), - anchor = codex.editor.draw.node('A', '', { href : url }); + blockquote.dataset.instgrmVersion = 4; - blockquote.dataset.instgrmVersion = 4; + paragraph.appendChild(anchor); + div.appendChild(paragraph); + blockquote.appendChild(div); - paragraph.appendChild(anchor); - div.appendChild(paragraph); - blockquote.appendChild(div); - - return blockquote; - - } - }; + return blockquote; + } + }; /** * Prepare before usage * Load important scripts to render embed */ - instagram_plugin.prepare = function() { + instagram_plugin.prepare = function () { + return new Promise(function (resolve, reject) { + codex.editor.core.importScript('https://platform.instagram.com/en_US/embeds.js', 'instagram-api').then(function () { + resolve(); + }).catch(function () { + reject(Error('Instagram API was not loaded')); + }); + }); + }; - return new Promise(function(resolve, reject){ - - codex.editor.core.importScript("https://platform.instagram.com/en_US/embeds.js", 'instagram-api').then(function(){ - resolve(); - }).catch(function(){ - reject(Error('Instagram API was not loaded')); - }); - - }); - }; - - /** + /** * @private * * Make instagram embed via Widgets method */ - var make_ = function(data, isInternal) { + var make_ = function (data, isInternal) { + if (!data.instagram_url) + return; - if (!data.instagram_url) - return; + var block = methods.instagramBlock(data.instagram_url); - var block = methods.instagramBlock(data.instagram_url); + if (isInternal) { + setTimeout(function () { + /** Render block */ + methods.render(block); + }, 200); + } - if (isInternal) { + if (!isInternal) { + methods.render(block); + } - setTimeout(function() { + return block; + }; - /** Render block */ - methods.render(block); + instagram_plugin.validate = function (data) { + return true; + }; - }, 200); - } - - if (!isInternal) { - methods.render(block); - } - - return block; - }; - - instagram_plugin.validate = function(data) { - return true; - }; - - /** + /** * Saving JSON output. * Upload data via ajax */ - instagram_plugin.save = function(blockContent) { + instagram_plugin.save = function (blockContent) { + var data; - var data; - - if (!blockContent) - return; - - /** Example */ - data = { - instagram_url: blockContent.src - }; - - return data; + if (!blockContent) + return; + /** Example */ + data = { + instagram_url: blockContent.src }; - instagram_plugin.validate = function(data) { + return data; + }; - var checkUrl = new RegExp("http?.+instagram.com\/p?."); + instagram_plugin.validate = function (data) { + var checkUrl = new RegExp('http?.+instagram.com\/p?.'); - if (!data.instagram_url || checkUrl.exec(data.instagram_url).length == 0) - return; + if (!data.instagram_url || checkUrl.exec(data.instagram_url).length == 0) + return; - return true; - }; + return true; + }; - /** + /** * Render data */ - instagram_plugin.render = function(data) { - return make_(data); - }; + instagram_plugin.render = function (data) { + return make_(data); + }; - /** + /** * callback for instagram url's coming from pasteTool * Using instagram Embed Widgete to render * @param url */ - instagram_plugin.urlPastedCallback = function(url) { - var data = { - instagram_url: url - }; - - make_(data, true); - + instagram_plugin.urlPastedCallback = function (url) { + var data = { + instagram_url: url }; - instagram_plugin.pastePatterns = [ - { - type: 'instagram', - regex: /http?.+instagram.com\/p\/([a-zA-Z0-9]*)\S*/, - callback: instagram_plugin.urlPastedCallback - } - ]; + make_(data, true); + }; - instagram_plugin.destroy = function () { + instagram_plugin.pastePatterns = [ + { + type: 'instagram', + regex: /http?.+instagram.com\/p\/([a-zA-Z0-9]*)\S*/, + callback: instagram_plugin.urlPastedCallback + } + ]; - instagram = null; - delete window.instgrm - - }; - - return instagram_plugin; + instagram_plugin.destroy = function () { + instagram = null; + delete window.instgrm; + }; + return instagram_plugin; })({}); diff --git a/example/plugins/link/link.js b/example/plugins/link/link.js index 2763015f..9477d637 100644 --- a/example/plugins/link/link.js +++ b/example/plugins/link/link.js @@ -6,345 +6,296 @@ * Link tool plugin */ -var link = (function(link_plugin) { +var link = (function (link_plugin) { + var settings = { + defaultText : 'Вставьте ссылку ...', + ENTER_KEY : 13, + currentBlock : null, + currentInput : null, + elementClasses : { + link: 'tool-link-link', + image: 'tool-link-image', + title: 'tool-link-title', + description: 'tool-link-description', + loader: 'tool-link-loader', + error: 'tool-link-error' + } + }; - var settings = { - defaultText : 'Вставьте ссылку ...', - ENTER_KEY : 13, - currentBlock : null, - currentInput : null, - elementClasses : { - link: "tool-link-link", - image: "tool-link-image", - title: "tool-link-title", - description: "tool-link-description", - loader: "tool-link-loader", - error: "tool-link-error" - } - }; + var ui = { - var ui = { + make : function (json) { + var wrapper = ui.wrapper(), + siteImage = ui.image(json.image, settings.elementClasses.image), + siteTitle = ui.title(json.title), + siteDescription = ui.description(json.description), + siteLink = ui.link(json.url, json.url); - make : function (json) { + wrapper.appendChild(siteImage); + wrapper.appendChild(siteTitle); + wrapper.appendChild(siteLink); + wrapper.appendChild(siteDescription); - var wrapper = ui.wrapper(), - siteImage = ui.image(json.image, settings.elementClasses.image), - siteTitle = ui.title(json.title), - siteDescription = ui.description(json.description), - siteLink = ui.link(json.url, json.url); + siteTitle.contentEditable = true; + siteDescription.contentEditable = true; - wrapper.appendChild(siteImage); - wrapper.appendChild(siteTitle); - wrapper.appendChild(siteLink); - wrapper.appendChild(siteDescription); + return wrapper; + }, - siteTitle.contentEditable = true; - siteDescription.contentEditable = true; + mainBlock : function () { + var wrapper = document.createElement('div'); - return wrapper; + wrapper.classList.add('ceditor-tool-link'); - }, + return wrapper; + }, - mainBlock : function () { + input : function () { + var inputTag = document.createElement('input'); - var wrapper = document.createElement('div'); + inputTag.classList.add('ceditor-tool-link-input'); - wrapper.classList.add("ceditor-tool-link"); + inputTag.placeholder = settings.defaultText; - return wrapper; + inputTag.contentEditable = false; - }, + return inputTag; + }, - input : function () { + wrapper : function () { + var wrapper = document.createElement('div'); - var inputTag = document.createElement('input'); + wrapper.classList.add('tool-link-panel', 'clearfix'); - inputTag.classList.add("ceditor-tool-link-input"); + return wrapper; + }, - inputTag.placeholder = settings.defaultText; + image : function (imageSrc, imageClass) { + var imageTag = document.createElement('img'); - inputTag.contentEditable = false; + imageTag.classList.add(imageClass); - return inputTag; + imageTag.setAttribute('src', imageSrc); - }, + return imageTag; + }, - wrapper : function () { + link : function (linkUrl, linkText) { + var linkTag = document.createElement('a'); - var wrapper = document.createElement('div'); + linkTag.classList.add(settings.elementClasses.link); - wrapper.classList.add('tool-link-panel', 'clearfix'); + linkTag.href = linkUrl; - return wrapper; + linkTag.target = '_blank'; - }, + linkTag.innerText = linkText; - image : function (imageSrc, imageClass) { + return linkTag; + }, - var imageTag = document.createElement('img'); + title : function (titleText) { + var titleTag = document.createElement('div'); - imageTag.classList.add(imageClass); + titleTag.classList.add('tool-link-content', settings.elementClasses.title); - imageTag.setAttribute('src', imageSrc); + titleTag.innerHTML = titleText; - return imageTag; + return titleTag; + }, - }, + description : function (descriptionText) { + var descriptionTag = document.createElement('div'); - link : function (linkUrl, linkText) { + descriptionTag.classList.add('tool-link-content', settings.elementClasses.description); - var linkTag = document.createElement('a'); + descriptionTag.innerHTML = descriptionText; - linkTag.classList.add(settings.elementClasses.link); + return descriptionTag; + } - linkTag.href = linkUrl; + }; - linkTag.target = "_blank"; + var methods = { - linkTag.innerText = linkText; + blockPasteCallback : function (event) { + var clipboardData = event.clipboardData || window.clipboardData, + pastedData = clipboardData.getData('Text'), + block = event.target.parentNode; - return linkTag; + methods.renderLink(pastedData, block); - }, + event.stopPropagation(); + }, - title : function (titleText) { + blockKeyDownCallback : function (event) { + var inputTag = event.target, + block = inputTag.parentNode, + url; - var titleTag = document.createElement('div'); + if ( block.classList.contains(settings.elementClasses.error) ) { + block.classList.remove(settings.elementClasses.error); + } - titleTag.classList.add("tool-link-content", settings.elementClasses.title); + if (event.keyCode == settings.ENTER_KEY) { + url = inputTag.value; - titleTag.innerHTML = titleText; + methods.renderLink(url, block); - return titleTag; - }, + event.preventDefault(); + } + }, - description : function (descriptionText) { + renderLink : function (url, block) { + Promise.resolve() - var descriptionTag = document.createElement('div'); + .then(function () { + return methods.urlify(url); + }) - descriptionTag.classList.add("tool-link-content", settings.elementClasses.description); + .then(function (url) { + /* Show loader gif **/ + block.classList.add(settings.elementClasses.loader); - descriptionTag.innerHTML = descriptionText; + return fetch( link_plugin.config.fetchUrl + '?url=' + encodeURI(url) ); + }) - return descriptionTag; - } + .then(function (response) { + if (response.status == '200') { + return response.json(); + } else { + return Error('Invalid response status: %o', response); + } + }) - }; + .then(function (json) { + methods.composeLinkPreview(json, block); + }) - var methods = { + .catch(function (error) { + /* Hide loader gif **/ + block.classList.remove(settings.elementClasses.loader); - blockPasteCallback : function (event) { + block.classList.add(settings.elementClasses.error); - var clipboardData = event.clipboardData || window.clipboardData, - pastedData = clipboardData.getData('Text'), - block = event.target.parentNode; + codex.editor.core.log('Error while doing things with link paste: %o', 'error', error); + }); + }, - methods.renderLink(pastedData, block); + urlify : function (text) { + var urlRegex = /(https?:\/\/\S+)/g; - event.stopPropagation(); + var links = text.match(urlRegex); - }, + if (links) { + return links[0]; + } - blockKeyDownCallback : function (event) { + return Promise.reject(Error('Url is not matched')); + }, - var inputTag = event.target, - block = inputTag.parentNode, - url; + composeLinkPreview : function (json, currentBlock) { + if (json == {}) { + return; + } - if ( block.classList.contains(settings.elementClasses.error) ) { - block.classList.remove(settings.elementClasses.error); - } + var previewBlock = ui.make(json); - if (event.keyCode == settings.ENTER_KEY) { + settings.currentInput.remove(); - url = inputTag.value; + currentBlock.appendChild(previewBlock); - methods.renderLink(url, block); + currentBlock.classList.remove(settings.elementClasses.loader); + } + }; - event.preventDefault(); - } - }, + link_plugin.prepare = function (config) { + link_plugin.config = config; - renderLink : function (url, block) { + return Promise.resolve(); + }; - Promise.resolve() - - .then(function () { - return methods.urlify(url); - }) - - .then(function (url) { - - /* Show loader gif **/ - block.classList.add(settings.elementClasses.loader); - - return fetch( link_plugin.config.fetchUrl + '?url=' + encodeURI(url) ); - }) - - .then(function (response) { - - if (response.status == "200"){ - - return response.json(); - - } else { - - return Error("Invalid response status: %o", response); - - } - - }) - - .then(function (json) { - methods.composeLinkPreview(json, block); - }) - - .catch(function(error) { - - /* Hide loader gif **/ - block.classList.remove(settings.elementClasses.loader); - - block.classList.add(settings.elementClasses.error); - - codex.editor.core.log('Error while doing things with link paste: %o', 'error', error); - }); - - }, - - urlify : function (text) { - - var urlRegex = /(https?:\/\/\S+)/g; - - var links = text.match(urlRegex); - - if (links) { - return links[0]; - } - - return Promise.reject(Error("Url is not matched")); - - }, - - composeLinkPreview : function (json, currentBlock) { - - if (json == {}) { - return; - } - - var previewBlock = ui.make(json); - - settings.currentInput.remove(); - - currentBlock.appendChild(previewBlock); - - currentBlock.classList.remove(settings.elementClasses.loader); - - } - }; - - link_plugin.prepare = function (config) { - - link_plugin.config = config; - - return Promise.resolve(); - - }; - - /** + /** * Make initial header block * @param {object} JSON with block data * @return {Element} element to append */ - link_plugin.makeNewBlock = function (data) { + link_plugin.makeNewBlock = function (data) { + var wrapper = ui.mainBlock(), + tag = ui.input(); - var wrapper = ui.mainBlock(), - tag = ui.input(); + settings.currentInput = tag; - settings.currentInput = tag; + wrapper.appendChild(tag); - wrapper.appendChild(tag); - - wrapper.classList.add('ce-link'); - /** + wrapper.classList.add('ce-link'); + /** * Bind callbacks **/ - tag.addEventListener('paste', methods.blockPasteCallback, false); - tag.addEventListener('keydown', methods.blockKeyDownCallback, false); + tag.addEventListener('paste', methods.blockPasteCallback, false); + tag.addEventListener('keydown', methods.blockKeyDownCallback, false); - return wrapper; + return wrapper; + }; - }; - - /** + /** * Method to render HTML block from JSON */ - link_plugin.render = function (json) { + link_plugin.render = function (json) { + if ( json ) { + var block = ui.mainBlock(), + tag = ui.make(json); - if ( json ) { + block.classList.add('ce-link'); + block.appendChild(tag); - var block = ui.mainBlock(), - tag = ui.make(json); + return block; + } else { + var wrapper = ui.mainBlock(), + tag = ui.input(); - block.classList.add('ce-link'); - block.appendChild(tag); + settings.currentInput = tag; - return block; + wrapper.appendChild(tag); - } else { - - var wrapper = ui.mainBlock(), - tag = ui.input(); - - settings.currentInput = tag; - - wrapper.appendChild(tag); - - wrapper.classList.add('ce-link'); - /** + wrapper.classList.add('ce-link'); + /** * Bind callbacks **/ - tag.addEventListener('paste', methods.blockPasteCallback, false); - tag.addEventListener('keydown', methods.blockKeyDownCallback, false); + tag.addEventListener('paste', methods.blockPasteCallback, false); + tag.addEventListener('keydown', methods.blockKeyDownCallback, false); - return wrapper; - } + return wrapper; + } + }; + link_plugin.validate = function (data) { + if (data.url.trim() == '' || data.title.trim() == '' || data.description.trim() == '') + return; - }; + return true; + }; - link_plugin.validate = function (data) { - - if (data.url.trim() == '' || data.title.trim() == '' || data.description.trim() == '') - return; - - return true; - }; - - /** + /** * Method to extract JSON data from HTML block */ - link_plugin.save = function (blockContent){ - - var linkElement = settings.elementClasses.link; - - var data = { - url : blockContent.querySelector("." + linkElement).href, - shortLink : blockContent.querySelector("." + linkElement).textContent || '', - image : blockContent.querySelector("." + settings.elementClasses.image).src || '', - title : blockContent.querySelector("." + settings.elementClasses.title).textContent || '', - description : blockContent.querySelector("." + settings.elementClasses.description).textContent || '' - }; - - return data; + link_plugin.save = function (blockContent) { + var linkElement = settings.elementClasses.link; + var data = { + url : blockContent.querySelector('.' + linkElement).href, + shortLink : blockContent.querySelector('.' + linkElement).textContent || '', + image : blockContent.querySelector('.' + settings.elementClasses.image).src || '', + title : blockContent.querySelector('.' + settings.elementClasses.title).textContent || '', + description : blockContent.querySelector('.' + settings.elementClasses.description).textContent || '' }; - link_plugin.destroy = function () { + return data; + }; - link = null; - - }; - - return link_plugin; + link_plugin.destroy = function () { + link = null; + }; + return link_plugin; })({}); diff --git a/example/plugins/list/list.js b/example/plugins/list/list.js index 5cdef435..df356968 100644 --- a/example/plugins/list/list.js +++ b/example/plugins/list/list.js @@ -2,240 +2,208 @@ * Code Plugin\ * Creates code tag and adds content to this tag */ -var list = (function(list_plugin) { - - /** +var list = (function (list_plugin) { + /** * CSS class names */ - var elementClasses_ = { - pluginWrapper: 'cdx-plugin-list', - li: 'cdx-plugin-list__li', - settings: 'cdx-plugin-list__settings', - settingsItem: 'cdx-plugin-settings__item' - }; + var elementClasses_ = { + pluginWrapper: 'cdx-plugin-list', + li: 'cdx-plugin-list__li', + settings: 'cdx-plugin-list__settings', + settingsItem: 'cdx-plugin-settings__item' + }; - var LIST_ITEM_TAG = 'LI'; + var LIST_ITEM_TAG = 'LI'; - var ui = { + var ui = { - make: function (blockType) { + make: function (blockType) { + var wrapper = this.block(blockType || 'UL', elementClasses_.pluginWrapper); - var wrapper = this.block(blockType || 'UL', elementClasses_.pluginWrapper); + wrapper.dataset.type = blockType; + wrapper.contentEditable = true; - wrapper.dataset.type = blockType; - wrapper.contentEditable = true; + wrapper.addEventListener('keydown', methods_.keyDown); - wrapper.addEventListener('keydown', methods_.keyDown); + return wrapper; + }, - return wrapper; + block: function (blockType, blockClass) { + var block = document.createElement(blockType); + if (blockClass) block.classList.add(blockClass); + + return block; + }, + + button: function (buttonType) { + var types = { + unordered: 'Обычный', + ordered: 'Нумерованный' }, + button = document.createElement('DIV'); - block: function (blockType, blockClass) { + button.innerHTML = types[buttonType]; - var block = document.createElement(blockType); + button.classList.add(elementClasses_.settingsItem); - if (blockClass) block.classList.add(blockClass); + return button; + } + }; - return block; + var methods_ = { - }, - - button: function (buttonType) { - - var types = { - unordered: 'Обычный', - ordered: 'Нумерованный' - }, - button = document.createElement('DIV'); - - button.innerHTML = types[buttonType]; - - button.classList.add(elementClasses_.settingsItem); - - return button; - } - }; - - var methods_ = { - - /** + /** * Changes block type => OL or UL * @param event * @param blockType */ - changeBlockStyle : function (event, blockType) { + changeBlockStyle : function (event, blockType) { + var currentBlock = codex.editor.content.currentNode, + newEditable = ui.make(blockType), + oldEditable = currentBlock.querySelector('[contenteditable]'); - var currentBlock = codex.editor.content.currentNode, - newEditable = ui.make(blockType), - oldEditable = currentBlock.querySelector("[contenteditable]"); + newEditable.dataset.type = blockType; + newEditable.innerHTML = oldEditable.innerHTML; + newEditable.classList.add(elementClasses_.pluginWrapper); - newEditable.dataset.type = blockType; - newEditable.innerHTML = oldEditable.innerHTML; - newEditable.classList.add(elementClasses_.pluginWrapper); + codex.editor.content.switchBlock(currentBlock, newEditable, 'list'); + }, + keyDown: function (e) { + var controlKeyPressed = e.ctrlKey || e.metaKey, + keyCodeForA = 65; - codex.editor.content.switchBlock(currentBlock, newEditable, 'list'); - }, - keyDown: function (e) { - - var controlKeyPressed = e.ctrlKey || e.metaKey, - keyCodeForA = 65; - - /** + /** * If CTRL+A (CMD+A) was pressed, we should select only one list item, * not all
      or */ - if (controlKeyPressed && e.keyCode == keyCodeForA) { - - e.preventDefault(); - - /** - * Select
    1. content - */ - methods_.selectListItem(); - - } - - }, + if (controlKeyPressed && e.keyCode == keyCodeForA) { + e.preventDefault(); /** + * Select
    2. content + */ + methods_.selectListItem(); + } + }, + + /** * Select all content of
    3. with caret */ - selectListItem : function () { + selectListItem : function () { + var selection = window.getSelection(), + currentSelectedNode = selection.anchorNode.parentNode, + range = new Range(); - var selection = window.getSelection(), - currentSelectedNode = selection.anchorNode.parentNode, - range = new Range(); - - /** + /** * Search for
    4. element */ - while ( currentSelectedNode && currentSelectedNode.tagName != LIST_ITEM_TAG ) { + while ( currentSelectedNode && currentSelectedNode.tagName != LIST_ITEM_TAG ) { + currentSelectedNode = currentSelectedNode.parentNode; + } - currentSelectedNode = currentSelectedNode.parentNode; + range.selectNodeContents(currentSelectedNode); - } - - range.selectNodeContents(currentSelectedNode); - - selection.removeAllRanges(); - selection.addRange(range); - - } - }; + selection.removeAllRanges(); + selection.addRange(range); + } + }; /** * Method to render HTML block from JSON */ - list_plugin.render = function (data) { + list_plugin.render = function (data) { + var type = data && (data.type == 'ordered' || data.type == 'OL') ? 'OL' : 'UL', + tag = ui.make(type), + newLi; - var type = data && (data.type == 'ordered' || data.type == 'OL') ? 'OL' : 'UL', - tag = ui.make(type), - newLi; + if (data && data.items) { + data.items.forEach(function (element, index, array) { + newLi = ui.block('li', elementClasses_.li); - if (data && data.items) { + newLi.innerHTML = element || ''; - data.items.forEach(function (element, index, array) { + tag.appendChild(newLi); + }); + } else { + newLi = ui.block('li', elementClasses_.li); - newLi = ui.block('li', elementClasses_.li); + tag.appendChild(newLi); + } - newLi.innerHTML = element || ''; + return tag; + }; - tag.appendChild(newLi); + list_plugin.validate = function (data) { + var isEmpty = data.items.every(function (item) { + return item.trim() === ''; + }); - }); + if (isEmpty) { + return; + } - } else { + if (data.type != 'UL' && data.type != 'OL') { + console.warn('CodeX Editor List-tool: wrong list type passed %o', data.type); + return; + } - newLi = ui.block('li', elementClasses_.li); + return true; + }; - tag.appendChild(newLi); - - } - - return tag; - - }; - - list_plugin.validate = function(data) { - - var isEmpty = data.items.every(function(item){ - return item.trim() === ''; - }); - - if (isEmpty){ - return; - } - - if (data.type != 'UL' && data.type != 'OL'){ - console.warn('CodeX Editor List-tool: wrong list type passed %o', data.type); - return; - } - - return true; - }; - - /** + /** * Method to extract JSON data from HTML block */ - list_plugin.save = function (blockContent){ + list_plugin.save = function (blockContent) { + var data = { + type : null, + items : [] + }, + litsItemContent = '', + isEmptyItem = false; - var data = { - type : null, - items : [] - }, - litsItemContent = '', - isEmptyItem = false; + for (var index = 0; index < blockContent.childNodes.length; index++) { + litsItemContent = blockContent.childNodes[index].innerHTML; + isEmptyItem = !blockContent.childNodes[index].textContent.trim(); - for (var index = 0; index < blockContent.childNodes.length; index++){ + if (!isEmptyItem) { + data.items.push(litsItemContent); + } + } - litsItemContent = blockContent.childNodes[index].innerHTML; - isEmptyItem = !blockContent.childNodes[index].textContent.trim(); + data.type = blockContent.dataset.type; - if (!isEmptyItem) { - data.items.push(litsItemContent); - } - } + return data; + }; - data.type = blockContent.dataset.type; + list_plugin.makeSettings = function () { + var holder = document.createElement('DIV'); - return data; + /** Add holder classname */ + holder.className = elementClasses_.settings; - }; + var orderedButton = ui.button('ordered'), + unorderedButton = ui.button('unordered'); - list_plugin.makeSettings = function () { + orderedButton.addEventListener('click', function (event) { + methods_.changeBlockStyle(event, 'OL'); + codex.editor.toolbar.settings.close(); + }); - var holder = document.createElement('DIV'); + unorderedButton.addEventListener('click', function (event) { + methods_.changeBlockStyle(event, 'UL'); + codex.editor.toolbar.settings.close(); + }); - /** Add holder classname */ - holder.className = elementClasses_.settings; + holder.appendChild(orderedButton); + holder.appendChild(unorderedButton); - var orderedButton = ui.button("ordered"), - unorderedButton = ui.button("unordered"); + return holder; + }; - orderedButton.addEventListener('click', function (event) { - methods_.changeBlockStyle(event, 'OL'); - codex.editor.toolbar.settings.close(); - }); - - unorderedButton.addEventListener('click', function (event) { - methods_.changeBlockStyle(event, 'UL'); - codex.editor.toolbar.settings.close(); - }); - - holder.appendChild(orderedButton); - holder.appendChild(unorderedButton); - - return holder; - - }; - - list_plugin.destroy = function () { - - list = null; - - }; - - return list_plugin; + list_plugin.destroy = function () { + list = null; + }; + return list_plugin; })({}); diff --git a/example/plugins/quote/quote.js b/example/plugins/quote/quote.js index 45c7a8b6..61d1fba7 100644 --- a/example/plugins/quote/quote.js +++ b/example/plugins/quote/quote.js @@ -3,344 +3,310 @@ * Quote plugin */ -var quote = (function(quote_plugin) { - - /** +var quote = (function (quote_plugin) { + /** * @private * * CSS styles */ - var elementClasses_ = { + var elementClasses_ = { - ce_quote : 'ce-quote', - quoteText : 'ce_quote--text', - quoteAuthor : 'ce_quote--author', - authorsJob : 'ce_quote--job', - authorsPhoto : 'authorsPhoto', - authorsPhotoWrapper : 'authorsPhoto-wrapper', - authorsPhotoWrapper_preview : 'authorsPhotoWrapper_preview', + ce_quote : 'ce-quote', + quoteText : 'ce_quote--text', + quoteAuthor : 'ce_quote--author', + authorsJob : 'ce_quote--job', + authorsPhoto : 'authorsPhoto', + authorsPhotoWrapper : 'authorsPhoto-wrapper', + authorsPhotoWrapper_preview : 'authorsPhotoWrapper_preview', - simple : { - text : 'quoteStyle-simple--text' - }, + simple : { + text : 'quoteStyle-simple--text' + }, - withCaption : { - blockquote : 'quoteStyle-withCaption--blockquote', - author : 'quoteStyle-withCaption--author' - }, + withCaption : { + blockquote : 'quoteStyle-withCaption--blockquote', + author : 'quoteStyle-withCaption--author' + }, - withPhoto : { - photo : 'quoteStyle-withPhoto--photo', - author : 'quoteStyle-withPhoto--author', - job : 'quoteStyle-withPhoto--job', - quote : 'quoteStyle-withPhoto--quote', - wrapper : 'quoteStyle-withPhoto--wrapper', - authorHolder : 'quoteStyle-withPhoto--authorWrapper' - }, + withPhoto : { + photo : 'quoteStyle-withPhoto--photo', + author : 'quoteStyle-withPhoto--author', + job : 'quoteStyle-withPhoto--job', + quote : 'quoteStyle-withPhoto--quote', + wrapper : 'quoteStyle-withPhoto--wrapper', + authorHolder : 'quoteStyle-withPhoto--authorWrapper' + }, - settings : { - holder : 'cdx-plugin-settings--horisontal', - caption : 'ce_plugin_quote--caption', - buttons : 'cdx-plugin-settings__item', - selectedType : 'ce-quote-settings--selected' - } - }; + settings : { + holder : 'cdx-plugin-settings--horisontal', + caption : 'ce_plugin_quote--caption', + buttons : 'cdx-plugin-settings__item', + selectedType : 'ce-quote-settings--selected' + } + }; /** * @private * * */ - var methods_ = { + var methods_ = { - changeStyleClicked : function() { + changeStyleClicked : function () { + var changeStyleButton = this, + quote = codex.editor.content.currentNode.querySelector('.' + elementClasses_.ce_quote), + newStyle = changeStyleButton.dataset.style, + styleSelectors = this.parentNode.childNodes; - var changeStyleButton = this, - quote = codex.editor.content.currentNode.querySelector('.' + elementClasses_.ce_quote), - newStyle = changeStyleButton.dataset.style, - styleSelectors = this.parentNode.childNodes; + quote.dataset.quoteStyle = newStyle; - quote.dataset.quoteStyle = newStyle; - - /** + /** * Mark selected style button */ - for (var i = styleSelectors.length - 1; i >= 0; i--) { - styleSelectors[i].classList.remove(elementClasses_.settings.selectedType); - } + for (var i = styleSelectors.length - 1; i >= 0; i--) { + styleSelectors[i].classList.remove(elementClasses_.settings.selectedType); + } - this.classList.add(elementClasses_.settings.selectedType); + this.classList.add(elementClasses_.settings.selectedType); + }, - }, - - /** + /** * @deprecated */ - selectTypeQuoteStyle : function(type) { + selectTypeQuoteStyle : function (type) { + var quoteStyleFunction; - var quoteStyleFunction; - - /** + /** * Choose Quote style to replace */ - switch (type) { - case 'simple': - quoteStyleFunction = methods_.makeSimpleQuote; - break; - case 'withCaption': - quoteStyleFunction = methods_.makeQuoteWithCaption; - break; - case 'withPhoto': - quoteStyleFunction = methods_.makeQuoteWithPhoto; - break; - } + switch (type) { + case 'simple': + quoteStyleFunction = methods_.makeSimpleQuote; + break; + case 'withCaption': + quoteStyleFunction = methods_.makeQuoteWithCaption; + break; + case 'withPhoto': + quoteStyleFunction = methods_.makeQuoteWithPhoto; + break; + } - return quoteStyleFunction; + return quoteStyleFunction; + }, - }, - - /** + /** * @deprecated */ - addSelectTypeClickListener : function(el, quoteStyle) { - - el.addEventListener('click', function () { - - /** + addSelectTypeClickListener : function (el, quoteStyle) { + el.addEventListener('click', function () { + /** * Parsing currentNode to JSON. */ - var parsedOldQuote = methods_.parseBlockQuote(), - newStyledQuote = quoteStyle(parsedOldQuote); + var parsedOldQuote = methods_.parseBlockQuote(), + newStyledQuote = quoteStyle(parsedOldQuote); - var wrapper = codex.editor.content.composeNewBlock(newStyledQuote, 'quote'); - wrapper.appendChild(newStyledQuote); + var wrapper = codex.editor.content.composeNewBlock(newStyledQuote, 'quote'); - codex.editor.content.switchBlock(codex.editor.content.currentNode, newStyledQuote, 'quote'); + wrapper.appendChild(newStyledQuote); - /** Close settings after replacing */ - codex.editor.toolbar.settings.close(); + codex.editor.content.switchBlock(codex.editor.content.currentNode, newStyledQuote, 'quote'); - }, false); + /** Close settings after replacing */ + codex.editor.toolbar.settings.close(); + }, false); + }, - }, - - /** + /** * @deprecated */ - makeSimpleQuote : function(data) { + makeSimpleQuote : function (data) { + var wrapper = ui_.makeBlock('BLOCKQUOTE', [elementClasses_.simple.text, elementClasses_.quoteText]); - var wrapper = ui_.makeBlock('BLOCKQUOTE', [elementClasses_.simple.text, elementClasses_.quoteText]); + wrapper.innerHTML = data.text || ''; - wrapper.innerHTML = data.text || ''; + wrapper.dataset.quoteStyle = 'simple'; + wrapper.classList.add(elementClasses_.ce_quote); + wrapper.contentEditable = 'true'; - wrapper.dataset.quoteStyle = 'simple'; - wrapper.classList.add(elementClasses_.ce_quote); - wrapper.contentEditable = 'true'; + return wrapper; + }, - return wrapper; - }, - - /** + /** * @deprecated */ - makeQuoteWithCaption : function(data) { + makeQuoteWithCaption : function (data) { + var wrapper = ui_.blockquote(), + text = ui_.makeBlock('DIV', [elementClasses_.withCaption.blockquote, elementClasses_.quoteText]), + author = ui_.makeBlock('DIV', [elementClasses_.withCaption.author, elementClasses_.quoteAuthor]); - var wrapper = ui_.blockquote(), - text = ui_.makeBlock('DIV', [elementClasses_.withCaption.blockquote, elementClasses_.quoteText]), - author = ui_.makeBlock('DIV', [elementClasses_.withCaption.author, elementClasses_.quoteAuthor]); + /* make text block ontentEditable */ + text.contentEditable = 'true'; - /* make text block ontentEditable */ - text.contentEditable = 'true'; + text.innerHTML = data.text || ''; - text.innerHTML = data.text || ''; + /* make Author contentEditable */ + author.contentEditable = 'true'; - /* make Author contentEditable */ - author.contentEditable = 'true'; + author.innerHTML = data.cite || ''; - author.innerHTML = data.cite || ''; + /* Appending created components */ + wrapper.dataset.quoteStyle = 'withCaption'; + wrapper.classList.add(elementClasses_.ce_quote); - /* Appending created components */ - wrapper.dataset.quoteStyle = 'withCaption'; - wrapper.classList.add(elementClasses_.ce_quote); + wrapper.appendChild(text); + wrapper.appendChild(author); - wrapper.appendChild(text); - wrapper.appendChild(author); + return wrapper; + }, - return wrapper; + makeQuoteWithPhoto : function (data) { + var wrapper = ui_.blockquote(), + photo = ui_.makeBlock('DIV', [ elementClasses_.withPhoto.photo ]), + author = ui_.makeBlock('DIV', [elementClasses_.withPhoto.author, elementClasses_.quoteAuthor]), + job = ui_.makeBlock('DIV', [elementClasses_.withPhoto.job, elementClasses_.authorsJob]), + quote = ui_.makeBlock('DIV', [elementClasses_.withPhoto.quote, elementClasses_.quoteText]); - }, + /* Default Image src */ + if (!data.image) { + var icon = ui_.makeBlock('SPAN', [ 'ce-icon-picture' ]); - makeQuoteWithPhoto : function(data) { + photo.appendChild(icon); + } else { + var authorsPhoto = ui_.img(elementClasses_.authorsPhoto); - var wrapper = ui_.blockquote(), - photo = ui_.makeBlock('DIV', [elementClasses_.withPhoto.photo]), - author = ui_.makeBlock('DIV', [elementClasses_.withPhoto.author, elementClasses_.quoteAuthor]), - job = ui_.makeBlock('DIV', [elementClasses_.withPhoto.job, elementClasses_.authorsJob]), - quote = ui_.makeBlock('DIV', [elementClasses_.withPhoto.quote, elementClasses_.quoteText]); + authorsPhoto.src = data.image; + authorsPhoto.dataset.bigUrl = data.image; - /* Default Image src */ - if (!data.image) { - - var icon = ui_.makeBlock('SPAN', ['ce-icon-picture']); - photo.appendChild(icon); - - } else { - - var authorsPhoto = ui_.img(elementClasses_.authorsPhoto); - - authorsPhoto.src = data.image; - authorsPhoto.dataset.bigUrl = data.image; - - photo.classList.add(elementClasses_.authorsPhotoWrapper); - photo.appendChild(authorsPhoto); - } + photo.classList.add(elementClasses_.authorsPhotoWrapper); + photo.appendChild(authorsPhoto); + } - photo.addEventListener('click', fileUploadClicked_, false); + photo.addEventListener('click', fileUploadClicked_, false); - /* make author block contentEditable */ - author.contentEditable = 'true'; - author.innerHTML = data.cite || ''; + /* make author block contentEditable */ + author.contentEditable = 'true'; + author.innerHTML = data.cite || ''; - /* Author's position and job */ - job.contentEditable = 'true'; - job.innerHTML = data.caption || ''; + /* Author's position and job */ + job.contentEditable = 'true'; + job.innerHTML = data.caption || ''; - var authorsWrapper = ui_.makeBlock('DIV', [elementClasses_.withPhoto.authorHolder]); - authorsWrapper.appendChild(author); - authorsWrapper.appendChild(job); + var authorsWrapper = ui_.makeBlock('DIV', [ elementClasses_.withPhoto.authorHolder ]); - /* make quote text contentEditable */ - quote.contentEditable = 'true'; - quote.innerHTML = data.text || ''; + authorsWrapper.appendChild(author); + authorsWrapper.appendChild(job); - wrapper.classList.add(elementClasses_.ce_quote); - wrapper.classList.add(elementClasses_.withPhoto.wrapper); - wrapper.dataset.quoteStyle = 'withPhoto'; + /* make quote text contentEditable */ + quote.contentEditable = 'true'; + quote.innerHTML = data.text || ''; - wrapper.appendChild(quote); - wrapper.appendChild(photo); - wrapper.appendChild(authorsWrapper); + wrapper.classList.add(elementClasses_.ce_quote); + wrapper.classList.add(elementClasses_.withPhoto.wrapper); + wrapper.dataset.quoteStyle = 'withPhoto'; - return wrapper; - }, + wrapper.appendChild(quote); + wrapper.appendChild(photo); + wrapper.appendChild(authorsWrapper); - parseBlockQuote : function(block) { + return wrapper; + }, - var currentNode = block || codex.editor.content.currentNode, - photo = currentNode.getElementsByTagName('img')[0], - author = currentNode.querySelector('.' + elementClasses_.quoteAuthor), - job = currentNode.querySelector('.' + elementClasses_.authorsJob), - quote ; + parseBlockQuote : function (block) { + var currentNode = block || codex.editor.content.currentNode, + photo = currentNode.getElementsByTagName('img')[0], + author = currentNode.querySelector('.' + elementClasses_.quoteAuthor), + job = currentNode.querySelector('.' + elementClasses_.authorsJob), + quote ; - /** Simple quote text placed in Blockquote tag*/ - if ( currentNode.dataset.quoteStyle == 'simple' ){ + /** Simple quote text placed in Blockquote tag*/ + if ( currentNode.dataset.quoteStyle == 'simple' ) { + quote = currentNode.innerHTML || ''; + } else { + quote = currentNode.querySelector('.' + elementClasses_.quoteText).innerHTML; + } - quote = currentNode.innerHTML || ''; + if (job) { + job = job.innerHTML || ''; + } - } else { + if (author) { + author = author.innerHTML || ''; + } - quote = currentNode.querySelector('.' + elementClasses_.quoteText).innerHTML; + if (photo) { + photo = photo.dataset.bigUrl; + } - } + var data = { + style : currentNode.dataset.quoteStyle, + text : quote, + author : author, + job : job, + photo : photo + }; - if (job){ - - job = job.innerHTML || ''; - - } - - if (author){ - - author = author.innerHTML || ''; - - } - - if (photo){ - - photo = photo.dataset.bigUrl; - - } - - var data = { - style : currentNode.dataset.quoteStyle, - text : quote, - author : author, - job : job, - photo : photo - }; - - return data; - } - }; + return data; + } + }; /** * @private * * Author image Uploader */ - var fileUploadClicked_ = function() { + var fileUploadClicked_ = function () { + var beforeSend = photoUploadingCallbacks_.beforeSend, + success = photoUploadingCallbacks_.success, + error = photoUploadingCallbacks_.error; - var beforeSend = photoUploadingCallbacks_.beforeSend, - success = photoUploadingCallbacks_.success, - error = photoUploadingCallbacks_.error; - - codex.editor.transport.selectAndUpload({ - beforeSend: beforeSend, - success: success, - error: error - }); - - }; + codex.editor.transport.selectAndUpload({ + beforeSend: beforeSend, + success: success, + error: error + }); + }; /** * @private * */ - var ui_ = { + var ui_ = { - wrapper : function($classList) { + wrapper : function ($classList) { + var el = document.createElement('DIV'); - var el = document.createElement('DIV'); + el.classList.add($classList); - el.classList.add($classList); + return el; + }, - return el; + blockquote : function () { + var el = document.createElement('BLOCKQUOTE'); - }, + return el; + }, - blockquote : function() { + img : function (attribute) { + var imageTag = document.createElement('IMG'); - var el = document.createElement('BLOCKQUOTE'); + imageTag.classList.add(attribute); - return el; + return imageTag; + }, - }, + makeBlock : function (tag, classList) { + var el = document.createElement(tag); - img : function(attribute) { + if ( classList ) { + for( var i = 0; i < classList.length; i++) + el.className += ' ' + classList[i]; + } - var imageTag = document.createElement('IMG'); - imageTag.classList.add(attribute); + return el; + } - return imageTag; - }, - - makeBlock : function(tag, classList) { - - var el = document.createElement(tag); - - if ( classList ) { - - for( var i = 0; i < classList.length; i++) - el.className += ' ' + classList[i]; - - } - - return el; - - } - - }; + }; @@ -349,120 +315,111 @@ var quote = (function(quote_plugin) { * * Callbacks */ - var photoUploadingCallbacks_ = { + var photoUploadingCallbacks_ = { - preview_ : function(e) { + preview_ : function (e) { + var uploadImageWrapper = codex.editor.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo), + authorsPhoto = ui_.img(elementClasses_.authorsPhoto); - var uploadImageWrapper = codex.editor.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo), - authorsPhoto = ui_.img(elementClasses_.authorsPhoto); + /** Appending uploaded image */ + uploadImageWrapper.classList.add(elementClasses_.authorsPhotoWrapper, elementClasses_.authorsPhotoWrapper_preview); - /** Appending uploaded image */ - uploadImageWrapper.classList.add(elementClasses_.authorsPhotoWrapper, elementClasses_.authorsPhotoWrapper_preview); + authorsPhoto.src = e.target.result; - authorsPhoto.src = e.target.result; + /** Remove icon from image wrapper */ + uploadImageWrapper.innerHTML = ''; - /** Remove icon from image wrapper */ - uploadImageWrapper.innerHTML = ''; + uploadImageWrapper.appendChild(authorsPhoto); + }, - uploadImageWrapper.appendChild(authorsPhoto); - }, + beforeSend : function () { + var input = codex.editor.transport.input, + files = input.files, + file = files[0], + fileReader = new FileReader(); - beforeSend : function() { + fileReader.readAsDataURL(file); - var input = codex.editor.transport.input, - files = input.files, - file = files[0], - fileReader = new FileReader(); + fileReader.onload = photoUploadingCallbacks_.preview_; + }, - fileReader.readAsDataURL(file); - - fileReader.onload = photoUploadingCallbacks_.preview_; - - }, - - /** + /** * Success callbacks for uploaded photo. * Replace upload icon with uploaded photo */ - success : function(result) { + success : function (result) { + var parsed = JSON.parse(result), + filename = parsed.filename, + uploadImageWrapper = codex.editor.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo); - var parsed = JSON.parse(result), - filename = parsed.filename, - uploadImageWrapper = codex.editor.content.currentNode.querySelector('.' + elementClasses_.withPhoto.photo); + var img = uploadImageWrapper.querySelector('IMG'); - var img = uploadImageWrapper.querySelector('IMG'); - img.src = parsed.data.file.bigUrl; - img.dataset.bigUrl = parsed.data.file.bigUrl; + img.src = parsed.data.file.bigUrl; + img.dataset.bigUrl = parsed.data.file.bigUrl; - uploadImageWrapper.classList.remove(elementClasses_.authorsPhotoWrapper_preview); - }, + uploadImageWrapper.classList.remove(elementClasses_.authorsPhotoWrapper_preview); + }, - /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */ - error : function(result) { - console.log('Can\'t upload an image'); - } + /** Error callback. Sends notification to user that something happend or plugin doesn't supports method */ + error : function (result) { + console.log('Can\'t upload an image'); + } - }; + }; /** * @private * * Make Quote from JSON datasets */ - var make_ = function(data) { + var make_ = function (data) { + var tag; - var tag; + if (data && data.size) { + data.style = quote_plugin.config.defaultStyle; - if (data && data.size) { - - data.style = quote_plugin.config.defaultStyle; - - /** + /** * Supported types */ - switch (data.style) { + switch (data.style) { + case 'simple': + tag = methods_.makeSimpleQuote(data); + break; + case 'withCaption': + tag = methods_.makeQuoteWithCaption(data); + break; + case 'withPhoto': + tag = methods_.makeQuoteWithPhoto(data); + break; + } - case 'simple': - tag = methods_.makeSimpleQuote(data); - break; - case 'withCaption': - tag = methods_.makeQuoteWithCaption(data); - break; - case 'withPhoto': - tag = methods_.makeQuoteWithPhoto(data); - break; - } + tag.dataset.quoteStyle = data.size; + } else { + var settings = { + 'text' : null, + 'format' : 'html', + 'cite' : null, + 'caption': null, + 'size' : null, + 'image' : null + }; - tag.dataset.quoteStyle = data.size; + tag = methods_.makeQuoteWithPhoto(settings); + } - } else { + return tag; + }; - var settings = { - "text" : null, - "format" : "html", - "cite" : null, - "caption": null, - "size" : null, - "image" : null - }; + var prepareDataForSave_ = function (data) { + if (data.size == 'withPhoto') { + data.size = 'small'; + } - tag = methods_.makeQuoteWithPhoto(settings); - } + /** Make paragraphs */ + data.text = codex.editor.content.wrapTextWithParagraphs(data.text); - return tag; - }; - - var prepareDataForSave_ = function(data) { - - if (data.size == 'withPhoto') { - data.size = 'small'; - } - - /** Make paragraphs */ - data.text = codex.editor.content.wrapTextWithParagraphs(data.text); - - return data; - }; + return data; + }; /** * @public @@ -471,115 +428,105 @@ var quote = (function(quote_plugin) { * * @param data */ - quote_plugin.render = function(data) { - return make_(data); - }; + quote_plugin.render = function (data) { + return make_(data); + }; - quote_plugin.validate = function(output) { + quote_plugin.validate = function (output) { + if (typeof output.text != 'string') { + return; + } - if (typeof output.text != "string") { - return; - } + return output; + }; - return output; - }; - - quote_plugin.save = function(blockContent) { - - /** + quote_plugin.save = function (blockContent) { + /** * Extracts JSON quote data from HTML block * @param {Text} text, {Text} author, {Object} photo */ - var parsedblock = methods_.parseBlockQuote(blockContent); + var parsedblock = methods_.parseBlockQuote(blockContent); - var outputData = { - "text" : parsedblock.text, - "format" : "html", - "cite" : parsedblock.author || '', - "caption": parsedblock.job || '', - "size" : parsedblock.style, - "image" : parsedblock.photo - }; - - return prepareDataForSave_(outputData); + var outputData = { + 'text' : parsedblock.text, + 'format' : 'html', + 'cite' : parsedblock.author || '', + 'caption': parsedblock.job || '', + 'size' : parsedblock.style, + 'image' : parsedblock.photo }; - /** + return prepareDataForSave_(outputData); + }; + + /** * @public * * Draws settings */ - quote_plugin.makeSettings = function(data) { + quote_plugin.makeSettings = function (data) { + var holder = document.createElement('DIV'), + types = { + big : 'По центру', + small : 'Врезка' + }, + selectTypeButton; - var holder = document.createElement('DIV'), - types = { - big : 'По центру', - small : 'Врезка' - }, - selectTypeButton; + /** Add holder classname */ + holder.className = elementClasses_.settings.holder; - /** Add holder classname */ - holder.className = elementClasses_.settings.holder; + /** Now add type selectors */ + for (var type in types) { + selectTypeButton = document.createElement('SPAN'); - /** Now add type selectors */ - for (var type in types){ + selectTypeButton.textContent = types[type]; + selectTypeButton.className = elementClasses_.settings.buttons; - selectTypeButton = document.createElement('SPAN'); + selectTypeButton.dataset.style = type; - selectTypeButton.textContent = types[type]; - selectTypeButton.className = elementClasses_.settings.buttons; + if ( type == quote_plugin.config.defaultStyle ) { + selectTypeButton.classList.add(quoteTools.styles.settings.selectedType); + } - selectTypeButton.dataset.style = type; + // var quoteStyle = quoteTools.selectTypeQuoteStyle(type); - if ( type == quote_plugin.config.defaultStyle ){ - selectTypeButton.classList.add(quoteTools.styles.settings.selectedType); - } + selectTypeButton.addEventListener('click', methods_.changeStyleClicked, false); + // quoteTools.addSelectTypeClickListener(selectTypeButton, quoteStyle); - // var quoteStyle = quoteTools.selectTypeQuoteStyle(type); + holder.appendChild(selectTypeButton); + } - selectTypeButton.addEventListener('click', methods_.changeStyleClicked, false); - // quoteTools.addSelectTypeClickListener(selectTypeButton, quoteStyle); + return holder; + }; - holder.appendChild(selectTypeButton); - - } - - return holder; - - }; - - /** + /** * @public * Default path to redactors images * @type {null} */ - quote_plugin.path = null; + quote_plugin.path = null; - /** + /** * @public * * @type {null} */ - quote_plugin.config = null; + quote_plugin.config = null; - /** + /** * @public * * @param config */ - quote_plugin.prepare = function(config) { + quote_plugin.prepare = function (config) { + quote_plugin.config = config; - quote_plugin.config = config; + return Promise.resolve(); + }; - return Promise.resolve(); - }; - - quote_plugin.destroy = function () { - - quote = null; - - }; - - return quote_plugin; + quote_plugin.destroy = function () { + quote = null; + }; + return quote_plugin; })({}); \ No newline at end of file diff --git a/example/plugins/raw/raw.js b/example/plugins/raw/raw.js index d63c29f1..1818f409 100644 --- a/example/plugins/raw/raw.js +++ b/example/plugins/raw/raw.js @@ -3,49 +3,37 @@ * Implements RAW-data block */ var rawPlugin = function (plugin) { + var editor = codex.editor; - var editor = codex.editor; + plugin.render = function (data) { + var input = editor.draw.node('TEXTAREA', 'raw-plugin__input', {}); - plugin.render = function (data) { + input.placeholder = 'Вставьте HTML код'; - var input = editor.draw.node('TEXTAREA', 'raw-plugin__input', {}); + if (data && data.raw) { + input.value = data.raw; + } - input.placeholder = 'Вставьте HTML код'; - - if (data && data.raw) { - input.value = data.raw; - } - - return input; + return input; + }; + plugin.save = function (block) { + return { + raw: block.value }; + }; - plugin.save = function (block) { + plugin.validate = function (data) { + if (data.raw.trim() === '') { + return; + } - return { - raw: block.value - }; + return true; + }; - }; - - plugin.validate = function (data) { - - if (data.raw.trim() === '') { - - return; - - } - - return true; - - }; - - plugin.destroy = function () { - - rawPlugin = null; - - }; - - return plugin; + plugin.destroy = function () { + rawPlugin = null; + }; + return plugin; }({}); \ No newline at end of file diff --git a/example/plugins/text/text.js b/example/plugins/text/text.js index f1f90364..f0c3f35f 100644 --- a/example/plugins/text/text.js +++ b/example/plugins/text/text.js @@ -7,7 +7,8 @@ * @license The MIT License (MIT) * @version 2.0.1 */ - /** + +/** * @typedef {Object} TextData * @description Tool's input and output data format * @property {String} text — Paragraph's content. Can include HTML tags: diff --git a/example/plugins/twitter/twitter.js b/example/plugins/twitter/twitter.js index 762fe6e9..84fe5dbe 100644 --- a/example/plugins/twitter/twitter.js +++ b/example/plugins/twitter/twitter.js @@ -3,276 +3,254 @@ * @version 1.0.0 */ -var twitter = (function(twitter_plugin) { - - /** +var twitter = (function (twitter_plugin) { + /** * User's configuration object */ - var config_ = {}; + var config_ = {}; - /** + /** * CSS classes */ - var css_ = { - pluginWrapper : 'cdx-tweet' - }; + var css_ = { + pluginWrapper : 'cdx-tweet' + }; - var methods = { + var methods = { - /** + /** * Twitter render method appends content after block * @param tweetId */ - twitter : function(data, twitterBlock) { + twitter : function (data, twitterBlock) { + var tweet = methods.drawTwitterHolder(), + twittersCaption = methods.drawTwittersCaptionBlock(); - var tweet = methods.drawTwitterHolder(), - twittersCaption = methods.drawTwittersCaptionBlock(); + if (data.caption) { + twittersCaption.innerHTML = data.caption; + } - if (data.caption) { - twittersCaption.innerHTML = data.caption; - } - - /** + /** * add created tweet to holder */ - tweet.appendChild(twitterBlock); + tweet.appendChild(twitterBlock); - // setTimeout(function() { - window.twttr.widgets.createTweet(data.id_str, twitterBlock).then(tweetInsertedCallback_); - // }, 1000); + // setTimeout(function() { + window.twttr.widgets.createTweet(data.id_str, twitterBlock).then(tweetInsertedCallback_); + // }, 1000); - tweet.classList.add('ce-redactor__loader'); + tweet.classList.add('ce-redactor__loader'); - if (codex.editor.content.currentNode) { - tweet.dataset.statusUrl = data.status_url; - codex.editor.content.switchBlock(codex.editor.content.currentNode, tweet, 'tweet'); - } + if (codex.editor.content.currentNode) { + tweet.dataset.statusUrl = data.status_url; + codex.editor.content.switchBlock(codex.editor.content.currentNode, tweet, 'tweet'); + } - /** + /** * in case if we need extra data */ - if ( !data.user ) { + if ( !data.user ) { + codex.editor.core.ajax({ + url : config_.fetchUrl + '?tweetId=' + data.id_str, + type: 'GET', + success: function (result) { + methods.saveTwitterData(result, tweet); + } + }); + } else { + tweet.dataset.profileImageUrl = data.user.profile_image_url; + tweet.dataset.profileImageUrlHttps = data.user.profile_image_url_https; + tweet.dataset.screenName = data.user.screen_name; + tweet.dataset.name = data.user.name; + tweet.dataset.id = +data.id; + tweet.dataset.idStr = data.id_str; + tweet.dataset.text = data.text; + tweet.dataset.createdAt = data.created_at; + tweet.dataset.statusUrl = data.status_url; + tweet.dataset.media = data.media; - codex.editor.core.ajax({ - url : config_.fetchUrl + '?tweetId=' + data.id_str, - type: "GET", - success: function(result) { - methods.saveTwitterData(result, tweet); - } - }); + tweet.classList.remove('ce-redactor__loader'); + } - } else { - - tweet.dataset.profileImageUrl = data.user.profile_image_url; - tweet.dataset.profileImageUrlHttps = data.user.profile_image_url_https; - tweet.dataset.screenName = data.user.screen_name; - tweet.dataset.name = data.user.name; - tweet.dataset.id = +data.id; - tweet.dataset.idStr = data.id_str; - tweet.dataset.text = data.text; - tweet.dataset.createdAt = data.created_at; - tweet.dataset.statusUrl = data.status_url; - tweet.dataset.media = data.media; - - tweet.classList.remove('ce-redactor__loader'); - } - - /** + /** * add caption to tweet */ - setTimeout(function() { - tweet.appendChild(twittersCaption); - }, 1000); + setTimeout(function () { + tweet.appendChild(twittersCaption); + }, 1000); - return tweet; + return tweet; + }, - }, + drawTwitterHolder : function () { + var block = document.createElement('DIV'); - drawTwitterHolder : function() { + block.classList.add(css_.pluginWrapper); - var block = document.createElement('DIV'); + return block; + }, - block.classList.add(css_.pluginWrapper); + drawTwitterBlock : function () { + var block = codex.editor.draw.node('DIV', '', { height: '20px' }); - return block; + return block; + }, - }, + drawTwittersCaptionBlock : function () { + var block = codex.editor.draw.node('DIV', [ 'ce-twitter__caption' ], { contentEditable : true }); - drawTwitterBlock : function() { - var block = codex.editor.draw.node('DIV', '', { height: "20px" }); - return block; - }, + return block; + }, - drawTwittersCaptionBlock : function() { - var block = codex.editor.draw.node('DIV', ['ce-twitter__caption'], { contentEditable : true }); - return block; - }, + saveTwitterData : function (result, tweet) { + var data = JSON.parse(result), + twitterContent = tweet; - saveTwitterData : function(result, tweet) { - - var data = JSON.parse(result), - twitterContent = tweet; - - setTimeout(function() { - - /** + setTimeout(function () { + /** * Save twitter data via data-attributes */ - twitterContent.dataset.profileImageUrl = data.user.profile_image_url; - twitterContent.dataset.profileImageUrlHttps = data.user.profile_image_url_https; - twitterContent.dataset.screenName = data.user.screen_name; - twitterContent.dataset.name = data.user.name; - twitterContent.dataset.id = +data.id; - twitterContent.dataset.idStr = data.id_str; - twitterContent.dataset.text = data.text; - twitterContent.dataset.createdAt = data.created_at; - twitterContent.dataset.media = data.entities.urls.length > 0 ? "false" : "true"; - - }, 50); - - } - }; + twitterContent.dataset.profileImageUrl = data.user.profile_image_url; + twitterContent.dataset.profileImageUrlHttps = data.user.profile_image_url_https; + twitterContent.dataset.screenName = data.user.screen_name; + twitterContent.dataset.name = data.user.name; + twitterContent.dataset.id = +data.id; + twitterContent.dataset.idStr = data.id_str; + twitterContent.dataset.text = data.text; + twitterContent.dataset.createdAt = data.created_at; + twitterContent.dataset.media = data.entities.urls.length > 0 ? 'false' : 'true'; + }, 50); + } + }; /** * @private * Fires after tweet widget rendered */ - function tweetInsertedCallback_(widget) { + function tweetInsertedCallback_(widget) { + var pluginWrapper = findParent_( widget, css_.pluginWrapper ); - var pluginWrapper = findParent_( widget , css_.pluginWrapper ); + pluginWrapper.classList.remove('ce-redactor__loader'); + } - pluginWrapper.classList.remove('ce-redactor__loader'); - - } - - /** + /** * @private * Find closiest parent Element with CSS class */ - function findParent_ (el, cls) { - while ((el = el.parentElement) && !el.classList.contains(cls)); - return el; - } + function findParent_(el, cls) { + while ((el = el.parentElement) && !el.classList.contains(cls)); + return el; + } - /** + /** * Prepare twitter scripts * @param {object} config */ - twitter_plugin.prepare = function(config) { - - /** + twitter_plugin.prepare = function (config) { + /** * Save configs */ - config_ = config; + config_ = config; - return new Promise(function(resolve, reject){ + return new Promise(function (resolve, reject) { + codex.editor.core.importScript('https://platform.twitter.com/widgets.js', 'twitter-api').then(function () { + resolve(); + }).catch(function () { + reject(Error('Twitter API was not loaded')); + }); + }); + }; - codex.editor.core.importScript("https://platform.twitter.com/widgets.js", 'twitter-api').then(function(){ - resolve(); - }).catch(function(){ - reject(Error('Twitter API was not loaded')); - }); - - }); - - }; - - /** + /** * @private * * @param data * @returns {*} */ - make_ = function(data) { + make_ = function (data) { + if (!data.id || !data.status_url) + return; - if (!data.id || !data.status_url) - return; + if (!data.id_str) { + data.id_str = data.status_url.match(/[^\/]+$/)[0]; + } - if (!data.id_str) { - data.id_str = data.status_url.match(/[^\/]+$/)[0]; - } + var twitterBlock = methods.drawTwitterBlock(); - var twitterBlock = methods.drawTwitterBlock(); + var tweet = methods.twitter(data, twitterBlock); - var tweet = methods.twitter(data, twitterBlock); + return tweet; + }; - return tweet; + twitter_plugin.validate = function (data) { + return true; + }; + + twitter_plugin.save = function (blockContent) { + var data, + caption = blockContent.querySelector('.ce-twitter__caption'); + + data = { + media:blockContent.dataset.media, + conversation:false, + user:{ + profile_image_url: blockContent.dataset.profileImageUrl, + profile_image_url_https: blockContent.dataset.profileImageUrlHttps, + screen_name: blockContent.dataset.screenName, + name: blockContent.dataset.name + }, + id: blockContent.dataset.id || blockContent.dataset.tweetId, + id_str : blockContent.dataset.idStr, + text: blockContent.dataset.text, + created_at: blockContent.dataset.createdAt, + status_url: blockContent.dataset.statusUrl, + caption: caption.innerHTML || '' }; - twitter_plugin.validate = function(data) { - return true; + return data; + }; + + twitter_plugin.render = function (data) { + return make_(data); + }; + + twitter_plugin.urlPastedCallback = function (url) { + var tweetId, + arr, + data; + + arr = url.split('/'); + tweetId = arr.pop(); + + /** Example */ + data = { + 'media' : true, + 'conversation' : false, + 'user' : null, + 'id' : +tweetId, + 'text' : null, + 'created_at' : null, + 'status_url' : url, + 'caption' : null }; - twitter_plugin.save = function(blockContent) { + make_(data); + }; - var data, - caption = blockContent.querySelector('.ce-twitter__caption'); + twitter_plugin.pastePatterns = [ + { + type: 'twitter', + regex: /http?.+twitter.com?.+\//, + callback: twitter_plugin.urlPastedCallback + } + ]; - data = { - media:blockContent.dataset.media, - conversation:false, - user:{ - profile_image_url: blockContent.dataset.profileImageUrl, - profile_image_url_https: blockContent.dataset.profileImageUrlHttps, - screen_name: blockContent.dataset.screenName, - name: blockContent.dataset.name - }, - id: blockContent.dataset.id || blockContent.dataset.tweetId, - id_str : blockContent.dataset.idStr, - text: blockContent.dataset.text, - created_at: blockContent.dataset.createdAt, - status_url: blockContent.dataset.statusUrl, - caption: caption.innerHTML || '' - }; - - return data; - }; - - twitter_plugin.render = function(data) { - return make_(data); - }; - - twitter_plugin.urlPastedCallback = function(url) { - - var tweetId, - arr, - data; - - arr = url.split('/'); - tweetId = arr.pop(); - - /** Example */ - data = { - "media" : true, - "conversation" : false, - "user" : null, - "id" : +tweetId, - "text" : null, - "created_at" : null, - "status_url" : url, - "caption" : null - }; - - make_(data); - }; - - twitter_plugin.pastePatterns = [ - { - type: 'twitter', - regex: /http?.+twitter.com?.+\//, - callback: twitter_plugin.urlPastedCallback - } - ]; - - twitter_plugin.destroy = function () { - - twitter = null; - delete window.twttr; - - }; - - return twitter_plugin; + twitter_plugin.destroy = function () { + twitter = null; + delete window.twttr; + }; + return twitter_plugin; })({}); diff --git a/src/components/core.js b/src/components/core.js index 9d0ef702..9b71fda7 100644 --- a/src/components/core.js +++ b/src/components/core.js @@ -5,79 +5,69 @@ * @version 2.0.0 */ export default class Core { - - /** + /** * Module key name * @returns {string} */ - static get name() { + static get name() { + return 'core'; + }; - return 'core'; + /** Editor script prefixes */ + static get scriptPrefix() { + return 'cdx-script-'; + } - }; - - /** Editor script prefixes */ - static get scriptPrefix() { - - return 'cdx-script-'; - - } - - /** + /** * * @param Editor * @param Editor.modules {@link Tools#list} * @param Editor.config {@link CodexEditor#configuration} */ - constructor(config) { + constructor(config) { + // this.Editor.modules.toolbar; - // this.Editor.modules.toolbar; + this.Editor = null; - this.Editor = null; - - // console.log(this.Editor); + // console.log(this.Editor); - // this.toolbar = modules.toolbar; + // this.toolbar = modules.toolbar; - // this.sanitizer = null; - // this.state = {}; + // this.sanitizer = null; + // this.state = {}; + } - } - - /** + /** * @param Editor * @param Editor.modules {@link CodexEditor#moduleInstances} * @param Editor.config {@link CodexEditor#configuration} * @param Editor */ - set state(Editor) { + set state(Editor) { + this.Editor = Editor; + } - this.Editor = Editor; - - } - - /** + /** * @public * * Editor preparing method * @return Promise */ - prepare() { + prepare() { + // let self = this; - // let self = this; + console.log('Core prepare fired'); - console.log('Core prepare fired'); - - /** + /** * Обращение к другому модулю */ - console.log(this.Editor.ui.wrapper); + console.log(this.Editor.ui.wrapper); - return; + return; - /** + /** return new Promise(function (resolve, reject) { @@ -96,149 +86,107 @@ export default class Core { }); */ - - } + } - /** + /** * Native Ajax * @param {String} settings.url - request URL * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks * @param {function} settings.success * @param {function} settings.progress */ - ajax(settings) { + ajax(settings) { + if (!settings || !settings.url) { + return; + } - if (!settings || !settings.url) { - - return; - - } - - var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'), - encodedString, - isFormData, - prop; + var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'), + encodedString, + isFormData, + prop; - settings.async = true; - settings.type = settings.type || 'GET'; - settings.data = settings.data || ''; - settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8'; + settings.async = true; + settings.type = settings.type || 'GET'; + settings.data = settings.data || ''; + settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8'; - if (settings.type == 'GET' && settings.data) { + if (settings.type == 'GET' && settings.data) { + settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data; + } else { + encodedString = ''; + for(prop in settings.data) { + encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&'); + } + } - settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data; + if (settings.withCredentials) { + XMLHTTP.withCredentials = true; + } - } else { - - encodedString = ''; - for(prop in settings.data) { - - encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&'); - - } - - } - - if (settings.withCredentials) { - - XMLHTTP.withCredentials = true; - - } - - /** + /** * Value returned in beforeSend funtion will be passed as context to the other response callbacks * If beforeSend returns false, AJAX will be blocked */ - let responseContext, - beforeSendResult; + let responseContext, + beforeSendResult; - if (typeof settings.beforeSend === 'function') { - - beforeSendResult = settings.beforeSend.call(); - - if (beforeSendResult === false) { - - return; - - } - - } - - XMLHTTP.open( settings.type, settings.url, settings.async ); - - /** - * If we send FormData, we need no content-type header - */ - isFormData = isFormData_(settings.data); - - if (!isFormData) { - - if (settings.type !== 'POST') { - - XMLHTTP.setRequestHeader('Content-type', settings['content-type']); - - } else { - - XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - - } - - } - - XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - - responseContext = beforeSendResult || XMLHTTP; - - if (typeof settings.progress === 'function') { - - XMLHTTP.upload.onprogress = settings.progress.bind(responseContext); - - } - - XMLHTTP.onreadystatechange = function () { - - if (XMLHTTP.readyState === 4) { - - if (XMLHTTP.status === 200) { - - if (typeof settings.success === 'function') { - - settings.success.call(responseContext, XMLHTTP.responseText); - - } - - } else { - - if (typeof settings.error === 'function') { - - settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status); - - } - - } - - } - - }; - - if (isFormData) { - - // Sending FormData - XMLHTTP.send(settings.data); - - } else { - - // POST requests - XMLHTTP.send(encodedString); - - } - - return XMLHTTP; + if (typeof settings.beforeSend === 'function') { + beforeSendResult = settings.beforeSend.call(); + if (beforeSendResult === false) { + return; + } } + XMLHTTP.open( settings.type, settings.url, settings.async ); + + /** + * If we send FormData, we need no content-type header + */ + isFormData = isFormData_(settings.data); + + if (!isFormData) { + if (settings.type !== 'POST') { + XMLHTTP.setRequestHeader('Content-type', settings['content-type']); + } else { + XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + } + } + + XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + + responseContext = beforeSendResult || XMLHTTP; + + if (typeof settings.progress === 'function') { + XMLHTTP.upload.onprogress = settings.progress.bind(responseContext); + } + + XMLHTTP.onreadystatechange = function () { + if (XMLHTTP.readyState === 4) { + if (XMLHTTP.status === 200) { + if (typeof settings.success === 'function') { + settings.success.call(responseContext, XMLHTTP.responseText); + } + } else { + if (typeof settings.error === 'function') { + settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status); + } + } + } + }; + + if (isFormData) { + // Sending FormData + XMLHTTP.send(settings.data); + } else { + // POST requests + XMLHTTP.send(encodedString); + } + + return XMLHTTP; + } }; // module.exports = (function (core) { // diff --git a/src/components/draw.js b/src/components/draw.js index d416cecd..b08ab242 100644 --- a/src/components/draw.js +++ b/src/components/draw.js @@ -6,72 +6,61 @@ */ export default (function (draw) { + draw.ceBlock = function () { + var block = document.createElement('DIV'); - draw.ceBlock = function () { + block.className += 'ce_block'; - var block = document.createElement('DIV'); + return block; + }; - block.className += 'ce_block'; - - return block; - - }; - - /** + /** * Inline toolbar */ - draw.inlineToolbar = function () { + draw.inlineToolbar = function () { + var bar = document.createElement('DIV'); - var bar = document.createElement('DIV'); + bar.className += 'ce-toolbar-inline'; - bar.className += 'ce-toolbar-inline'; + return bar; + }; - return bar; - - }; - - /** + /** * Wrapper for inline toobar buttons */ - draw.inlineToolbarButtons = function () { + draw.inlineToolbarButtons = function () { + var wrapper = document.createElement('DIV'); - var wrapper = document.createElement('DIV'); + wrapper.className += 'ce-toolbar-inline__buttons'; - wrapper.className += 'ce-toolbar-inline__buttons'; + return wrapper; + }; - return wrapper; - - }; - - /** + /** * For some actions */ - draw.inlineToolbarActions = function () { + draw.inlineToolbarActions = function () { + var wrapper = document.createElement('DIV'); - var wrapper = document.createElement('DIV'); + wrapper.className += 'ce-toolbar-inline__actions'; - wrapper.className += 'ce-toolbar-inline__actions'; + return wrapper; + }; - return wrapper; + draw.inputForLink = function () { + var input = document.createElement('INPUT'); - }; + input.type = 'input'; + input.className += 'inputForLink'; + input.placeholder = 'Вставьте ссылку ...'; + input.setAttribute('form', 'defaultForm'); - draw.inputForLink = function () { + input.setAttribute('autofocus', 'autofocus'); - var input = document.createElement('INPUT'); + return input; + }; - input.type = 'input'; - input.className += 'inputForLink'; - input.placeholder = 'Вставьте ссылку ...'; - input.setAttribute('form', 'defaultForm'); - - input.setAttribute('autofocus', 'autofocus'); - - return input; - - }; - - /** + /** * @protected * * Draws tool buttons for toolbox @@ -80,27 +69,25 @@ export default (function (draw) { * @param {String} classname * @returns {Element} */ - draw.toolbarButton = function (type, classname) { + draw.toolbarButton = function (type, classname) { + var button = document.createElement('li'), + toolIcon = document.createElement('i'), + toolTitle = document.createElement('span'); - var button = document.createElement('li'), - toolIcon = document.createElement('i'), - toolTitle = document.createElement('span'); + button.dataset.type = type; + button.setAttribute('title', type); - button.dataset.type = type; - button.setAttribute('title', type); - - toolIcon.classList.add(classname); - toolTitle.classList.add('ce_toolbar_tools--title'); + toolIcon.classList.add(classname); + toolTitle.classList.add('ce_toolbar_tools--title'); - button.appendChild(toolIcon); - button.appendChild(toolTitle); + button.appendChild(toolIcon); + button.appendChild(toolTitle); - return button; + return button; + }; - }; - - /** + /** * @protected * * Draws tools for inline toolbar @@ -108,73 +95,60 @@ export default (function (draw) { * @param {String} type * @param {String} classname */ - draw.toolbarButtonInline = function (type, classname) { + draw.toolbarButtonInline = function (type, classname) { + var button = document.createElement('BUTTON'), + toolIcon = document.createElement('I'); - var button = document.createElement('BUTTON'), - toolIcon = document.createElement('I'); + button.type = 'button'; + button.dataset.type = type; + toolIcon.classList.add(classname); - button.type = 'button'; - button.dataset.type = type; - toolIcon.classList.add(classname); + button.appendChild(toolIcon); - button.appendChild(toolIcon); + return button; + }; - return button; - - }; - - /** + /** * Redactor block */ - draw.block = function (tagName, content) { + draw.block = function (tagName, content) { + var node = document.createElement(tagName); - var node = document.createElement(tagName); + node.innerHTML = content || ''; - node.innerHTML = content || ''; + return node; + }; - return node; - - }; - - /** + /** * Creates Node with passed tagName and className * @param {string} tagName * @param {string} className * @param {object} properties - allow to assign properties */ - draw.node = function ( tagName, className, properties ) { + draw.node = function ( tagName, className, properties ) { + var el = document.createElement( tagName ); - var el = document.createElement( tagName ); + if ( className ) el.className = className; - if ( className ) el.className = className; + if ( properties ) { + for (var name in properties) { + el[name] = properties[name]; + } + } - if ( properties ) { + return el; + }; - for (var name in properties) { - - el[name] = properties[name]; - - } - - } - - return el; - - }; - - /** + /** * Unavailable plugin block */ - draw.unavailableBlock = function () { + draw.unavailableBlock = function () { + var wrapper = document.createElement('DIV'); - var wrapper = document.createElement('DIV'); + wrapper.classList.add('cdx-unavailable-block'); - wrapper.classList.add('cdx-unavailable-block'); - - return wrapper; - - }; - - return draw; + return wrapper; + }; + return draw; })({}); \ No newline at end of file diff --git a/src/components/modules/_anchors.js b/src/components/modules/_anchors.js index d72deaa4..00defbd4 100644 --- a/src/components/modules/_anchors.js +++ b/src/components/modules/_anchors.js @@ -6,87 +6,65 @@ */ module.exports = function (anchors) { + let editor = codex.editor; - let editor = codex.editor; + anchors.input = null; + anchors.currentNode = null; - anchors.input = null; - anchors.currentNode = null; + anchors.settingsOpened = function (currentBlock) { + anchors.currentNode = currentBlock; + anchors.input.value = anchors.currentNode.dataset.anchor || ''; + }; - anchors.settingsOpened = function (currentBlock) { + anchors.anchorChanged = function (e) { + var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value); - anchors.currentNode = currentBlock; - anchors.input.value = anchors.currentNode.dataset.anchor || ''; + anchors.currentNode.dataset.anchor = newAnchor; - }; + if (newAnchor.trim() !== '') { + anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR); + } else { + anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR); + } + }; - anchors.anchorChanged = function (e) { + anchors.keyDownOnAnchorInput = function (e) { + if (e.keyCode == editor.core.keys.ENTER) { + e.preventDefault(); + e.stopPropagation(); - var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value); + e.target.blur(); + editor.toolbar.settings.close(); + } + }; - anchors.currentNode.dataset.anchor = newAnchor; + anchors.keyUpOnAnchorInput = function (e) { + if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) { + e.stopPropagation(); + } + }; - if (newAnchor.trim() !== '') { + anchors.rusToTranslit = function (string) { + var ru = [ + 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', + 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', + 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я' + ], + en = [ + 'A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y', + 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', + 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya' + ]; - anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR); + for (var i = 0; i < ru.length; i++) { + string = string.split(ru[i]).join(en[i]); + string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase()); + } - } else { + string = string.replace(/[^0-9a-zA-Z_]+/g, '-'); - anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR); - - } - - }; - - anchors.keyDownOnAnchorInput = function (e) { - - if (e.keyCode == editor.core.keys.ENTER) { - - e.preventDefault(); - e.stopPropagation(); - - e.target.blur(); - editor.toolbar.settings.close(); - - } - - }; - - anchors.keyUpOnAnchorInput = function (e) { - - if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) { - - e.stopPropagation(); - - } - - }; - - anchors.rusToTranslit = function (string) { - - var ru = [ - 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', - 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', - 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я' - ], - en = [ - 'A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y', - 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', - 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya' - ]; - - for (var i = 0; i < ru.length; i++) { - - string = string.split(ru[i]).join(en[i]); - string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase()); - - } - - string = string.replace(/[^0-9a-zA-Z_]+/g, '-'); - - return string; - - }; - - return anchors; + return string; + }; + return anchors; }({}); \ No newline at end of file diff --git a/src/components/modules/_callbacks.js b/src/components/modules/_callbacks.js index 534e0705..a1407674 100644 --- a/src/components/modules/_callbacks.js +++ b/src/components/modules/_callbacks.js @@ -7,61 +7,48 @@ */ module.exports = (function (callbacks) { + let editor = codex.editor; - let editor = codex.editor; - - /** + /** * used by UI module * @description Routes all keydowns on document * @param {Object} event */ - callbacks.globalKeydown = function (event) { + callbacks.globalKeydown = function (event) { + switch (event.keyCode) { + case editor.core.keys.ENTER : enterKeyPressed_(event); break; + } + }; - switch (event.keyCode) { - - case editor.core.keys.ENTER : enterKeyPressed_(event); break; - - } - - }; - - /** + /** * used by UI module * @description Routes all keydowns on redactors area * @param {Object} event */ - callbacks.redactorKeyDown = function (event) { + callbacks.redactorKeyDown = function (event) { + switch (event.keyCode) { + case editor.core.keys.TAB : tabKeyPressedOnRedactorsZone_(event); break; + case editor.core.keys.ENTER : enterKeyPressedOnRedactorsZone_(event); break; + case editor.core.keys.ESC : escapeKeyPressedOnRedactorsZone_(event); break; + default : defaultKeyPressedOnRedactorsZone_(event); break; + } + }; - switch (event.keyCode) { - - case editor.core.keys.TAB : tabKeyPressedOnRedactorsZone_(event); break; - case editor.core.keys.ENTER : enterKeyPressedOnRedactorsZone_(event); break; - case editor.core.keys.ESC : escapeKeyPressedOnRedactorsZone_(event); break; - default : defaultKeyPressedOnRedactorsZone_(event); break; - - } - - }; - - /** + /** * used by UI module * @description Routes all keyup events * @param {Object} event */ - callbacks.globalKeyup = function (event) { + callbacks.globalKeyup = function (event) { + switch (event.keyCode) { + case editor.core.keys.UP : + case editor.core.keys.LEFT : + case editor.core.keys.RIGHT : + case editor.core.keys.DOWN : arrowKeyPressed_(event); break; + } + }; - switch (event.keyCode) { - - case editor.core.keys.UP : - case editor.core.keys.LEFT : - case editor.core.keys.RIGHT : - case editor.core.keys.DOWN : arrowKeyPressed_(event); break; - - } - - }; - - /** + /** * @param {Object} event * @private * @@ -69,59 +56,45 @@ module.exports = (function (callbacks) { * @description if Content is empty show toolbox (if it is closed) or leaf tools * uses Toolbars toolbox module to handle the situation */ - var tabKeyPressedOnRedactorsZone_ = function (event) { - - /** + var tabKeyPressedOnRedactorsZone_ = function (event) { + /** * Wait for solution. Would like to know the behaviour * @todo Add spaces */ - event.preventDefault(); + event.preventDefault(); - if (!editor.core.isBlockEmpty(editor.content.currentNode)) { + if (!editor.core.isBlockEmpty(editor.content.currentNode)) { + return; + } - return; + if ( !editor.toolbar.opened ) { + editor.toolbar.open(); + } - } - - if ( !editor.toolbar.opened ) { - - editor.toolbar.open(); - - } - - if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) { - - editor.toolbar.toolbox.open(); - - } else { - - editor.toolbar.toolbox.leaf(); - - } - - }; + if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) { + editor.toolbar.toolbox.open(); + } else { + editor.toolbar.toolbox.leaf(); + } + }; /** * Handles global EnterKey Press * @see enterPressedOnBlock_ * @param {Object} event */ - var enterKeyPressed_ = function () { - - if (editor.content.editorAreaHightlighted) { - - /** + var enterKeyPressed_ = function () { + if (editor.content.editorAreaHightlighted) { + /** * it means that we lose input index, saved index before is not correct * therefore we need to set caret when we insert new block */ - editor.caret.inputIndex = -1; + editor.caret.inputIndex = -1; - enterPressedOnBlock_(); - - } - - }; + enterPressedOnBlock_(); + } + }; /** * Callback for enter key pressing in first-level block area @@ -131,19 +104,17 @@ module.exports = (function (callbacks) { * * @description Inserts new block with initial type from settings */ - var enterPressedOnBlock_ = function () { + var enterPressedOnBlock_ = function () { + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; + editor.content.insertBlock({ + type : NEW_BLOCK_TYPE, + block : editor.tools[NEW_BLOCK_TYPE].render() + }, true ); - editor.content.insertBlock({ - type : NEW_BLOCK_TYPE, - block : editor.tools[NEW_BLOCK_TYPE].render() - }, true ); - - editor.toolbar.move(); - editor.toolbar.open(); - - }; + editor.toolbar.move(); + editor.toolbar.open(); + }; /** @@ -154,137 +125,119 @@ module.exports = (function (callbacks) { * * @description Makes new block with initial type from settings */ - var enterKeyPressedOnRedactorsZone_ = function (event) { + var enterKeyPressedOnRedactorsZone_ = function (event) { + if (event.target.contentEditable == 'true') { + /** Update input index */ + editor.caret.saveCurrentInputIndex(); + } - if (event.target.contentEditable == 'true') { - - /** Update input index */ - editor.caret.saveCurrentInputIndex(); - - } - - var currentInputIndex = editor.caret.getCurrentInputIndex() || 0, - workingNode = editor.content.currentNode, - tool = workingNode.dataset.tool, - isEnterPressedOnToolbar = editor.toolbar.opened && + var currentInputIndex = editor.caret.getCurrentInputIndex() || 0, + workingNode = editor.content.currentNode, + tool = workingNode.dataset.tool, + isEnterPressedOnToolbar = editor.toolbar.opened && editor.toolbar.current && event.target == editor.state.inputs[currentInputIndex]; - /** The list of tools which needs the default browser behaviour */ - var enableLineBreaks = editor.tools[tool].enableLineBreaks; + /** The list of tools which needs the default browser behaviour */ + var enableLineBreaks = editor.tools[tool].enableLineBreaks; - /** This type of block creates when enter is pressed */ - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; + /** This type of block creates when enter is pressed */ + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - /** + /** * When toolbar is opened, select tool instead of making new paragraph */ - if ( isEnterPressedOnToolbar ) { + if ( isEnterPressedOnToolbar ) { + event.preventDefault(); - event.preventDefault(); + editor.toolbar.toolbox.toolClicked(event); - editor.toolbar.toolbox.toolClicked(event); + editor.toolbar.close(); - editor.toolbar.close(); - - /** + /** * Stop other listeners callback executions */ - event.stopPropagation(); - event.stopImmediatePropagation(); + event.stopPropagation(); + event.stopImmediatePropagation(); - return; + return; + } - } - - /** + /** * Allow paragraph lineBreaks with shift enter * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation */ - if ( event.shiftKey || enableLineBreaks ) { + if ( event.shiftKey || enableLineBreaks ) { + event.stopPropagation(); + event.stopImmediatePropagation(); + return; + } - event.stopPropagation(); - event.stopImmediatePropagation(); - return; + var currentSelection = window.getSelection(), + currentSelectedNode = currentSelection.anchorNode, + caretAtTheEndOfText = editor.caret.position.atTheEnd(), + isTextNodeHasParentBetweenContenteditable = false; - } - - var currentSelection = window.getSelection(), - currentSelectedNode = currentSelection.anchorNode, - caretAtTheEndOfText = editor.caret.position.atTheEnd(), - isTextNodeHasParentBetweenContenteditable = false; - - /** + /** * Allow making new

      in same block by SHIFT+ENTER and forbids to prevent default browser behaviour */ - if ( event.shiftKey && !enableLineBreaks ) { + if ( event.shiftKey && !enableLineBreaks ) { + editor.callback.enterPressedOnBlock(editor.content.currentBlock, event); + event.preventDefault(); + return; + } - editor.callback.enterPressedOnBlock(editor.content.currentBlock, event); - event.preventDefault(); - return; - - } - - /** + /** * Workaround situation when caret at the Text node that has some wrapper Elements * Split block cant handle this. * We need to save default behavior */ - isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true'; + isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true'; - /** + /** * Split blocks when input has several nodes and caret placed in textNode */ - if ( - currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT && + if ( + currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT && !isTextNodeHasParentBetweenContenteditable && !caretAtTheEndOfText - ) { + ) { + event.preventDefault(); - event.preventDefault(); + editor.core.log('Splitting Text node...'); - editor.core.log('Splitting Text node...'); + editor.content.splitBlock(currentInputIndex); - editor.content.splitBlock(currentInputIndex); + /** Show plus button when next input after split is empty*/ + if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) { + editor.toolbar.showPlusButton(); + } + } else { + var islastNode = editor.content.isLastNode(currentSelectedNode); - /** Show plus button when next input after split is empty*/ - if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) { + if ( islastNode && caretAtTheEndOfText ) { + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); - editor.toolbar.showPlusButton(); + editor.core.log('ENTER clicked in last textNode. Create new BLOCK'); - } + editor.content.insertBlock({ + type: NEW_BLOCK_TYPE, + block: editor.tools[NEW_BLOCK_TYPE].render() + }, true); - } else { + editor.toolbar.move(); + editor.toolbar.open(); - var islastNode = editor.content.isLastNode(currentSelectedNode); + /** Show plus button with empty block */ + editor.toolbar.showPlusButton(); + } + } - if ( islastNode && caretAtTheEndOfText ) { - - event.preventDefault(); - event.stopPropagation(); - event.stopImmediatePropagation(); - - editor.core.log('ENTER clicked in last textNode. Create new BLOCK'); - - editor.content.insertBlock({ - type: NEW_BLOCK_TYPE, - block: editor.tools[NEW_BLOCK_TYPE].render() - }, true); - - editor.toolbar.move(); - editor.toolbar.open(); - - /** Show plus button with empty block */ - editor.toolbar.showPlusButton(); - - } - - } - - /** get all inputs after new appending block */ - editor.ui.saveInputs(); - - }; + /** get all inputs after new appending block */ + editor.ui.saveInputs(); + }; /** * Escape behaviour @@ -293,17 +246,15 @@ module.exports = (function (callbacks) { * * @description Closes toolbox and toolbar. Prevents default behaviour */ - var escapeKeyPressedOnRedactorsZone_ = function (event) { + var escapeKeyPressedOnRedactorsZone_ = function (event) { + /** Close all toolbar */ + editor.toolbar.close(); - /** Close all toolbar */ - editor.toolbar.close(); + /** Close toolbox */ + editor.toolbar.toolbox.close(); - /** Close toolbox */ - editor.toolbar.toolbox.close(); - - event.preventDefault(); - - }; + event.preventDefault(); + }; /** * @param {Event} event @@ -311,15 +262,13 @@ module.exports = (function (callbacks) { * * closes and moves toolbar */ - var arrowKeyPressed_ = function (event) { + var arrowKeyPressed_ = function (event) { + editor.content.workingNodeChanged(); - editor.content.workingNodeChanged(); - - /* Closing toolbar */ - editor.toolbar.close(); - editor.toolbar.move(); - - }; + /* Closing toolbar */ + editor.toolbar.close(); + editor.toolbar.move(); + }; /** * @private @@ -328,18 +277,14 @@ module.exports = (function (callbacks) { * @description Closes all opened bars from toolbar. * If block is mark, clears highlightning */ - var defaultKeyPressedOnRedactorsZone_ = function () { + var defaultKeyPressedOnRedactorsZone_ = function () { + editor.toolbar.close(); - editor.toolbar.close(); - - if (!editor.toolbar.inline.actionsOpened) { - - editor.toolbar.inline.close(); - editor.content.clearMark(); - - } - - }; + if (!editor.toolbar.inline.actionsOpened) { + editor.toolbar.inline.close(); + editor.content.clearMark(); + } + }; /** * Handler when clicked on redactors area @@ -354,114 +299,89 @@ module.exports = (function (callbacks) { * @see detectWhenClickedOnFirstLevelBlockArea_ * */ - callbacks.redactorClicked = function (event) { + callbacks.redactorClicked = function (event) { + detectWhenClickedOnFirstLevelBlockArea_(); - detectWhenClickedOnFirstLevelBlockArea_(); + editor.content.workingNodeChanged(event.target); + editor.ui.saveInputs(); - editor.content.workingNodeChanged(event.target); - editor.ui.saveInputs(); + var selectedText = editor.toolbar.inline.getSelectionText(), + firstLevelBlock; - var selectedText = editor.toolbar.inline.getSelectionText(), - firstLevelBlock; + /** If selection range took off, then we hide inline toolbar */ + if (selectedText.length === 0) { + editor.toolbar.inline.close(); + } - /** If selection range took off, then we hide inline toolbar */ - if (selectedText.length === 0) { + /** Update current input index in memory when caret focused into existed input */ + if (event.target.contentEditable == 'true') { + editor.caret.saveCurrentInputIndex(); + } - editor.toolbar.inline.close(); - - } - - /** Update current input index in memory when caret focused into existed input */ - if (event.target.contentEditable == 'true') { - - editor.caret.saveCurrentInputIndex(); - - } - - if (editor.content.currentNode === null) { - - /** + if (editor.content.currentNode === null) { + /** * If inputs in redactor does not exits, then we put input index 0 not -1 */ - var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0; + var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0; - /** If we have any inputs */ - if (editor.state.inputs.length) { + /** If we have any inputs */ + if (editor.state.inputs.length) { + /** getting firstlevel parent of input */ + firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]); + } - /** getting firstlevel parent of input */ - firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]); + /** If input is empty, then we set caret to the last input */ + if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) { + editor.caret.setToBlock(indexOfLastInput); + } else { + /** Create new input when caret clicked in redactors area */ + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - } - - /** If input is empty, then we set caret to the last input */ - if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) { - - editor.caret.setToBlock(indexOfLastInput); - - } else { - - /** Create new input when caret clicked in redactors area */ - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - - editor.content.insertBlock({ - type : NEW_BLOCK_TYPE, - block : editor.tools[NEW_BLOCK_TYPE].render() - }); - - /** If there is no inputs except inserted */ - if (editor.state.inputs.length === 1) { - - editor.caret.setToBlock(indexOfLastInput); - - } else { - - /** Set caret to this appended input */ - editor.caret.setToNextBlock(indexOfLastInput); - - } - - } + editor.content.insertBlock({ + type : NEW_BLOCK_TYPE, + block : editor.tools[NEW_BLOCK_TYPE].render() + }); + /** If there is no inputs except inserted */ + if (editor.state.inputs.length === 1) { + editor.caret.setToBlock(indexOfLastInput); } else { - - /** Close all panels */ - editor.toolbar.settings.close(); - editor.toolbar.toolbox.close(); - + /** Set caret to this appended input */ + editor.caret.setToNextBlock(indexOfLastInput); } - - /** - * Move toolbar and open - */ - editor.toolbar.move(); - editor.toolbar.open(); - - var inputIsEmpty = !editor.content.currentNode.textContent.trim(), - currentNodeType = editor.content.currentNode.dataset.tool, - isInitialType = currentNodeType == editor.settings.initialBlockPlugin; - - - /** Hide plus buttons */ - editor.toolbar.hidePlusButton(); - - if (!inputIsEmpty) { - - /** Mark current block */ - editor.content.markBlock(); - - } - - if ( isInitialType && inputIsEmpty ) { - - /** Show plus button */ - editor.toolbar.showPlusButton(); - - } - - - }; + } + } else { + /** Close all panels */ + editor.toolbar.settings.close(); + editor.toolbar.toolbox.close(); + } /** + * Move toolbar and open + */ + editor.toolbar.move(); + editor.toolbar.open(); + + var inputIsEmpty = !editor.content.currentNode.textContent.trim(), + currentNodeType = editor.content.currentNode.dataset.tool, + isInitialType = currentNodeType == editor.settings.initialBlockPlugin; + + + /** Hide plus buttons */ + editor.toolbar.hidePlusButton(); + + if (!inputIsEmpty) { + /** Mark current block */ + editor.content.markBlock(); + } + + if ( isInitialType && inputIsEmpty ) { + /** Show plus button */ + editor.toolbar.showPlusButton(); + } + }; + + /** * This method allows to define, is caret in contenteditable element or not. * * @private @@ -471,55 +391,39 @@ module.exports = (function (callbacks) { * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always * specifies to the first-level block. Other cases we just ignore. */ - var detectWhenClickedOnFirstLevelBlockArea_ = function () { + var detectWhenClickedOnFirstLevelBlockArea_ = function () { + var selection = window.getSelection(), + anchorNode = selection.anchorNode, + flag = false; - var selection = window.getSelection(), - anchorNode = selection.anchorNode, - flag = false; + if (selection.rangeCount === 0) { + editor.content.editorAreaHightlighted = true; + } else { + if (!editor.core.isDomNode(anchorNode)) { + anchorNode = anchorNode.parentNode; + } - if (selection.rangeCount === 0) { + /** Already founded, without loop */ + if (anchorNode.contentEditable == 'true') { + flag = true; + } - editor.content.editorAreaHightlighted = true; - - } else { - - if (!editor.core.isDomNode(anchorNode)) { - - anchorNode = anchorNode.parentNode; - - } - - /** Already founded, without loop */ - if (anchorNode.contentEditable == 'true') { - - flag = true; - - } - - while (anchorNode.contentEditable != 'true') { - - anchorNode = anchorNode.parentNode; - - if (anchorNode.contentEditable == 'true') { - - flag = true; - - } - - if (anchorNode == document.body) { - - break; - - } - - } - - /** If editable element founded, flag is "TRUE", Therefore we return "FALSE" */ - editor.content.editorAreaHightlighted = !flag; + while (anchorNode.contentEditable != 'true') { + anchorNode = anchorNode.parentNode; + if (anchorNode.contentEditable == 'true') { + flag = true; } - }; + if (anchorNode == document.body) { + break; + } + } + + /** If editable element founded, flag is "TRUE", Therefore we return "FALSE" */ + editor.content.editorAreaHightlighted = !flag; + } + }; /** * Toolbar button click handler @@ -529,35 +433,27 @@ module.exports = (function (callbacks) { * * @description gets current tool and calls render method */ - callbacks.toolbarButtonClicked = function (event) { + callbacks.toolbarButtonClicked = function (event) { + var button = this; - var button = this; + editor.toolbar.current = button.dataset.type; - editor.toolbar.current = button.dataset.type; + editor.toolbar.toolbox.toolClicked(event); + editor.toolbar.close(); + }; - editor.toolbar.toolbox.toolClicked(event); - editor.toolbar.close(); - - }; - - /** + /** * Show or Hide toolbox when plus button is clicked */ - callbacks.plusButtonClicked = function () { + callbacks.plusButtonClicked = function () { + if (!editor.nodes.toolbox.classList.contains('opened')) { + editor.toolbar.toolbox.open(); + } else { + editor.toolbar.toolbox.close(); + } + }; - if (!editor.nodes.toolbox.classList.contains('opened')) { - - editor.toolbar.toolbox.open(); - - } else { - - editor.toolbar.toolbox.close(); - - } - - }; - - /** + /** * Block handlers for KeyDown events * * @protected @@ -568,31 +464,27 @@ module.exports = (function (callbacks) { * @see backspacePressed_ * @see blockLeftOrUpArrowPressed_ */ - callbacks.blockKeydown = function (event) { + callbacks.blockKeydown = function (event) { + let block = event.target; // event.target is input - let block = event.target; // event.target is input + switch (event.keyCode) { + case editor.core.keys.DOWN: + case editor.core.keys.RIGHT: + blockRightOrDownArrowPressed_(event); + break; - switch (event.keyCode) { + case editor.core.keys.BACKSPACE: + backspacePressed_(block, event); + break; - case editor.core.keys.DOWN: - case editor.core.keys.RIGHT: - blockRightOrDownArrowPressed_(event); - break; + case editor.core.keys.UP: + case editor.core.keys.LEFT: + blockLeftOrUpArrowPressed_(event); + break; + } + }; - case editor.core.keys.BACKSPACE: - backspacePressed_(block, event); - break; - - case editor.core.keys.UP: - case editor.core.keys.LEFT: - blockLeftOrUpArrowPressed_(event); - break; - - } - - }; - - /** + /** * RIGHT or DOWN keydowns on block * * @param {Object} event @@ -602,82 +494,66 @@ module.exports = (function (callbacks) { * Uses method getDeepestTextNodeFromPosition to get the last node of next block * Sets caret if it is contenteditable */ - var blockRightOrDownArrowPressed_ = function (event) { + var blockRightOrDownArrowPressed_ = function (event) { + var selection = window.getSelection(), + inputs = editor.state.inputs, + focusedNode = selection.anchorNode, + focusedNodeHolder; - var selection = window.getSelection(), - inputs = editor.state.inputs, - focusedNode = selection.anchorNode, - focusedNodeHolder; + /** Check for caret existance */ + if (!focusedNode) { + return false; + } - /** Check for caret existance */ - if (!focusedNode) { + /** Looking for closest (parent) contentEditable element of focused node */ + while (focusedNode.contentEditable != 'true') { + focusedNodeHolder = focusedNode.parentNode; + focusedNode = focusedNodeHolder; + } - return false; + /** Input index in DOM level */ + var editableElementIndex = 0; - } + while (focusedNode != inputs[editableElementIndex]) { + editableElementIndex ++; + } - /** Looking for closest (parent) contentEditable element of focused node */ - while (focusedNode.contentEditable != 'true') { - - focusedNodeHolder = focusedNode.parentNode; - focusedNode = focusedNodeHolder; - - } - - /** Input index in DOM level */ - var editableElementIndex = 0; - - while (focusedNode != inputs[editableElementIndex]) { - - editableElementIndex ++; - - } - - /** + /** * Founded contentEditable element doesn't have childs * Or maybe New created block */ - if (!focusedNode.textContent) { + if (!focusedNode.textContent) { + editor.caret.setToNextBlock(editableElementIndex); + return; + } - editor.caret.setToNextBlock(editableElementIndex); - return; - - } - - /** + /** * Do nothing when caret doesn not reaches the end of last child */ - var caretInLastChild = false, - caretAtTheEndOfText = false; + var caretInLastChild = false, + caretAtTheEndOfText = false; - var lastChild, - deepestTextnode; + var lastChild, + deepestTextnode; - lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1 ]; + lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1 ]; - if (editor.core.isDomNode(lastChild)) { + if (editor.core.isDomNode(lastChild)) { + deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length); + } else { + deepestTextnode = lastChild; + } - deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length); + caretInLastChild = selection.anchorNode == deepestTextnode; + caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset; - } else { + if ( !caretInLastChild || !caretAtTheEndOfText ) { + editor.core.log('arrow [down|right] : caret does not reached the end'); + return false; + } - deepestTextnode = lastChild; - - } - - caretInLastChild = selection.anchorNode == deepestTextnode; - caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset; - - if ( !caretInLastChild || !caretAtTheEndOfText ) { - - editor.core.log('arrow [down|right] : caret does not reached the end'); - return false; - - } - - editor.caret.setToNextBlock(editableElementIndex); - - }; + editor.caret.setToNextBlock(editableElementIndex); + }; /** * LEFT or UP keydowns on block @@ -690,88 +566,70 @@ module.exports = (function (callbacks) { * Sets caret if it is contenteditable * */ - var blockLeftOrUpArrowPressed_ = function (event) { + var blockLeftOrUpArrowPressed_ = function (event) { + var selection = window.getSelection(), + inputs = editor.state.inputs, + focusedNode = selection.anchorNode, + focusedNodeHolder; - var selection = window.getSelection(), - inputs = editor.state.inputs, - focusedNode = selection.anchorNode, - focusedNodeHolder; + /** Check for caret existance */ + if (!focusedNode) { + return false; + } - /** Check for caret existance */ - if (!focusedNode) { - - return false; - - } - - /** + /** * LEFT or UP not at the beginning */ - if ( selection.anchorOffset !== 0) { + if ( selection.anchorOffset !== 0) { + return false; + } - return false; + /** Looking for parent contentEditable block */ + while (focusedNode.contentEditable != 'true') { + focusedNodeHolder = focusedNode.parentNode; + focusedNode = focusedNodeHolder; + } - } + /** Input index in DOM level */ + var editableElementIndex = 0; - /** Looking for parent contentEditable block */ - while (focusedNode.contentEditable != 'true') { + while (focusedNode != inputs[editableElementIndex]) { + editableElementIndex ++; + } - focusedNodeHolder = focusedNode.parentNode; - focusedNode = focusedNodeHolder; - - } - - /** Input index in DOM level */ - var editableElementIndex = 0; - - while (focusedNode != inputs[editableElementIndex]) { - - editableElementIndex ++; - - } - - /** + /** * Do nothing if caret is not at the beginning of first child */ - var caretInFirstChild = false, - caretAtTheBeginning = false; + var caretInFirstChild = false, + caretAtTheBeginning = false; - var firstChild, - deepestTextnode; + var firstChild, + deepestTextnode; - /** + /** * Founded contentEditable element doesn't have childs * Or maybe New created block */ - if (!focusedNode.textContent) { + if (!focusedNode.textContent) { + editor.caret.setToPreviousBlock(editableElementIndex); + return; + } - editor.caret.setToPreviousBlock(editableElementIndex); - return; + firstChild = focusedNode.childNodes[0]; - } + if (editor.core.isDomNode(firstChild)) { + deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0); + } else { + deepestTextnode = firstChild; + } - firstChild = focusedNode.childNodes[0]; + caretInFirstChild = selection.anchorNode == deepestTextnode; + caretAtTheBeginning = selection.anchorOffset === 0; - if (editor.core.isDomNode(firstChild)) { - - deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0); - - } else { - - deepestTextnode = firstChild; - - } - - caretInFirstChild = selection.anchorNode == deepestTextnode; - caretAtTheBeginning = selection.anchorOffset === 0; - - if ( caretInFirstChild && caretAtTheBeginning ) { - - editor.caret.setToPreviousBlock(editableElementIndex); - - } - - }; + if ( caretInFirstChild && caretAtTheBeginning ) { + editor.caret.setToPreviousBlock(editableElementIndex); + } + }; /** * Handles backspace keydown @@ -785,106 +643,78 @@ module.exports = (function (callbacks) { * But it we try'n to remove first block, then we should set caret to the next block, not previous. * If we removed the last block, create new one */ - var backspacePressed_ = function (block, event) { + var backspacePressed_ = function (block, event) { + var currentInputIndex = editor.caret.getCurrentInputIndex(), + range, + selectionLength, + firstLevelBlocksCount; - var currentInputIndex = editor.caret.getCurrentInputIndex(), - range, - selectionLength, - firstLevelBlocksCount; + if (editor.core.isNativeInput(event.target)) { + /** If input value is empty - remove block */ + if (event.target.value.trim() == '') { + block.remove(); + } else { + return; + } + } - if (editor.core.isNativeInput(event.target)) { + if (block.textContent.trim()) { + range = editor.content.getRange(); + selectionLength = range.endOffset - range.startOffset; - /** If input value is empty - remove block */ - if (event.target.value.trim() == '') { + if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) { + editor.content.mergeBlocks(currentInputIndex); + } else { + return; + } + } - block.remove(); - - } else { - - return; - - } - - } - - if (block.textContent.trim()) { - - range = editor.content.getRange(); - selectionLength = range.endOffset - range.startOffset; - - if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) { - - editor.content.mergeBlocks(currentInputIndex); - - } else { - - return; - - } - - } - - if (!selectionLength) { - - block.remove(); - - } + if (!selectionLength) { + block.remove(); + } - firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; + firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; - /** + /** * If all blocks are removed */ - if (firstLevelBlocksCount === 0) { + if (firstLevelBlocksCount === 0) { + /** update currentNode variable */ + editor.content.currentNode = null; - /** update currentNode variable */ - editor.content.currentNode = null; + /** Inserting new empty initial block */ + editor.ui.addInitialBlock(); - /** Inserting new empty initial block */ - editor.ui.addInitialBlock(); + /** Updating inputs state after deleting last block */ + editor.ui.saveInputs(); - /** Updating inputs state after deleting last block */ - editor.ui.saveInputs(); + /** Set to current appended block */ + window.setTimeout(function () { + editor.caret.setToPreviousBlock(1); + }, 10); + } else { + if (editor.caret.inputIndex !== 0) { + /** Target block is not first */ + editor.caret.setToPreviousBlock(editor.caret.inputIndex); + } else { + /** If we try to delete first block */ + editor.caret.setToNextBlock(editor.caret.inputIndex); + } + } - /** Set to current appended block */ - window.setTimeout(function () { + editor.toolbar.move(); - editor.caret.setToPreviousBlock(1); + if (!editor.toolbar.opened) { + editor.toolbar.open(); + } - }, 10); + /** Updating inputs state */ + editor.ui.saveInputs(); - } else { - - if (editor.caret.inputIndex !== 0) { - - /** Target block is not first */ - editor.caret.setToPreviousBlock(editor.caret.inputIndex); - - } else { - - /** If we try to delete first block */ - editor.caret.setToNextBlock(editor.caret.inputIndex); - - } - - } - - editor.toolbar.move(); - - if (!editor.toolbar.opened) { - - editor.toolbar.open(); - - } - - /** Updating inputs state */ - editor.ui.saveInputs(); - - /** Prevent default browser behaviour */ - event.preventDefault(); - - }; + /** Prevent default browser behaviour */ + event.preventDefault(); + }; /** * used by UI module @@ -894,24 +724,21 @@ module.exports = (function (callbacks) { * @protected * @description Opens toolbar settings */ - callbacks.showSettingsButtonClicked = function (event) { - - /** + callbacks.showSettingsButtonClicked = function (event) { + /** * Get type of current block * It uses to append settings from tool.settings property. * ... * Type is stored in data-type attribute on block */ - var currentToolType = editor.content.currentNode.dataset.tool; + var currentToolType = editor.content.currentNode.dataset.tool; - editor.toolbar.settings.toggle(currentToolType); + editor.toolbar.settings.toggle(currentToolType); - /** Close toolbox when settings button is active */ - editor.toolbar.toolbox.close(); - editor.toolbar.settings.hideRemoveActions(); - - }; - - return callbacks; + /** Close toolbox when settings button is active */ + editor.toolbar.toolbox.close(); + editor.toolbar.settings.hideRemoveActions(); + }; + return callbacks; })({}); \ No newline at end of file diff --git a/src/components/modules/_caret.js b/src/components/modules/_caret.js index 8c151709..ecae4c0c 100644 --- a/src/components/modules/_caret.js +++ b/src/components/modules/_caret.js @@ -6,300 +6,247 @@ */ module.exports = (function (caret) { + let editor = codex.editor; - let editor = codex.editor; - - /** + /** * @var {int} InputIndex - editable element in DOM */ - caret.inputIndex = null; + caret.inputIndex = null; - /** + /** * @var {int} offset - caret position in a text node. */ - caret.offset = null; + caret.offset = null; - /** + /** * @var {int} focusedNodeIndex - we get index of child node from first-level block */ - caret.focusedNodeIndex = null; + caret.focusedNodeIndex = null; - /** + /** * Creates Document Range and sets caret to the element. * @protected * @uses caret.save — if you need to save caret position * @param {Element} el - Changed Node. */ - caret.set = function ( el, index, offset) { + caret.set = function ( el, index, offset) { + offset = offset || caret.offset || 0; + index = index || caret.focusedNodeIndex || 0; - offset = offset || caret.offset || 0; - index = index || caret.focusedNodeIndex || 0; + var childs = el.childNodes, + nodeToSet; - var childs = el.childNodes, - nodeToSet; + if ( childs.length === 0 ) { + nodeToSet = el; + } else { + nodeToSet = childs[index]; + } - if ( childs.length === 0 ) { + /** If Element is INPUT */ + if (el.contentEditable != 'true') { + el.focus(); + return; + } - nodeToSet = el; + if (editor.core.isDomNode(nodeToSet)) { + nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length); + } - } else { + var range = document.createRange(), + selection = window.getSelection(); - nodeToSet = childs[index]; + window.setTimeout(function () { + range.setStart(nodeToSet, offset); + range.setEnd(nodeToSet, offset); - } + selection.removeAllRanges(); + selection.addRange(range); - /** If Element is INPUT */ - if (el.contentEditable != 'true') { + editor.caret.saveCurrentInputIndex(); + }, 20); + }; - el.focus(); - return; - - } - - if (editor.core.isDomNode(nodeToSet)) { - - nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length); - - } - - var range = document.createRange(), - selection = window.getSelection(); - - window.setTimeout(function () { - - range.setStart(nodeToSet, offset); - range.setEnd(nodeToSet, offset); - - selection.removeAllRanges(); - selection.addRange(range); - - editor.caret.saveCurrentInputIndex(); - - }, 20); - - }; - - /** + /** * @protected * Updates index of input and saves it in caret object */ - caret.saveCurrentInputIndex = function () { + caret.saveCurrentInputIndex = function () { + /** Index of Input that we paste sanitized content */ + var selection = window.getSelection(), + inputs = editor.state.inputs, + focusedNode = selection.anchorNode, + focusedNodeHolder; - /** Index of Input that we paste sanitized content */ - var selection = window.getSelection(), - inputs = editor.state.inputs, - focusedNode = selection.anchorNode, - focusedNodeHolder; + if (!focusedNode) { + return; + } - if (!focusedNode) { + /** Looking for parent contentEditable block */ + while (focusedNode.contentEditable != 'true') { + focusedNodeHolder = focusedNode.parentNode; + focusedNode = focusedNodeHolder; + } - return; + /** Input index in DOM level */ + var editableElementIndex = 0; - } + while (focusedNode != inputs[editableElementIndex]) { + editableElementIndex ++; + } - /** Looking for parent contentEditable block */ - while (focusedNode.contentEditable != 'true') { + caret.inputIndex = editableElementIndex; + }; - focusedNodeHolder = focusedNode.parentNode; - focusedNode = focusedNodeHolder; - - } - - /** Input index in DOM level */ - var editableElementIndex = 0; - - while (focusedNode != inputs[editableElementIndex]) { - - editableElementIndex ++; - - } - - caret.inputIndex = editableElementIndex; - - }; - - /** + /** * Returns current input index (caret object) */ - caret.getCurrentInputIndex = function () { + caret.getCurrentInputIndex = function () { + return caret.inputIndex; + }; - return caret.inputIndex; - - }; - - /** + /** * @param {int} index - index of first-level block after that we set caret into next input */ - caret.setToNextBlock = function (index) { + caret.setToNextBlock = function (index) { + var inputs = editor.state.inputs, + nextInput = inputs[index + 1]; - var inputs = editor.state.inputs, - nextInput = inputs[index + 1]; + if (!nextInput) { + editor.core.log('We are reached the end'); + return; + } - if (!nextInput) { - - editor.core.log('We are reached the end'); - return; - - } - - /** + /** * When new Block created or deleted content of input * We should add some text node to set caret */ - if (!nextInput.childNodes.length) { + if (!nextInput.childNodes.length) { + var emptyTextElement = document.createTextNode(''); - var emptyTextElement = document.createTextNode(''); + nextInput.appendChild(emptyTextElement); + } - nextInput.appendChild(emptyTextElement); + editor.caret.inputIndex = index + 1; + editor.caret.set(nextInput, 0, 0); + editor.content.workingNodeChanged(nextInput); + }; - } - - editor.caret.inputIndex = index + 1; - editor.caret.set(nextInput, 0, 0); - editor.content.workingNodeChanged(nextInput); - - }; - - /** + /** * @param {int} index - index of target input. * Sets caret to input with this index */ - caret.setToBlock = function (index) { + caret.setToBlock = function (index) { + var inputs = editor.state.inputs, + targetInput = inputs[index]; - var inputs = editor.state.inputs, - targetInput = inputs[index]; + if ( !targetInput ) { + return; + } - if ( !targetInput ) { - - return; - - } - - /** + /** * When new Block created or deleted content of input * We should add some text node to set caret */ - if (!targetInput.childNodes.length) { + if (!targetInput.childNodes.length) { + var emptyTextElement = document.createTextNode(''); - var emptyTextElement = document.createTextNode(''); + targetInput.appendChild(emptyTextElement); + } - targetInput.appendChild(emptyTextElement); + editor.caret.inputIndex = index; + editor.caret.set(targetInput, 0, 0); + editor.content.workingNodeChanged(targetInput); + }; - } - - editor.caret.inputIndex = index; - editor.caret.set(targetInput, 0, 0); - editor.content.workingNodeChanged(targetInput); - - }; - - /** + /** * @param {int} index - index of input */ - caret.setToPreviousBlock = function (index) { + caret.setToPreviousBlock = function (index) { + index = index || 0; - index = index || 0; - - var inputs = editor.state.inputs, - previousInput = inputs[index - 1], - lastChildNode, - lengthOfLastChildNode, - emptyTextElement; + var inputs = editor.state.inputs, + previousInput = inputs[index - 1], + lastChildNode, + lengthOfLastChildNode, + emptyTextElement; - if (!previousInput) { + if (!previousInput) { + editor.core.log('We are reached first node'); + return; + } - editor.core.log('We are reached first node'); - return; + lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length); + lengthOfLastChildNode = lastChildNode.length; - } - - lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length); - lengthOfLastChildNode = lastChildNode.length; - - /** + /** * When new Block created or deleted content of input * We should add some text node to set caret */ - if (!previousInput.childNodes.length) { + if (!previousInput.childNodes.length) { + emptyTextElement = document.createTextNode(''); + previousInput.appendChild(emptyTextElement); + } + editor.caret.inputIndex = index - 1; + editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode); + editor.content.workingNodeChanged(inputs[index - 1]); + }; - emptyTextElement = document.createTextNode(''); - previousInput.appendChild(emptyTextElement); + caret.position = { - } - editor.caret.inputIndex = index - 1; - editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode); - editor.content.workingNodeChanged(inputs[index - 1]); + atStart : function () { + var selection = window.getSelection(), + anchorOffset = selection.anchorOffset, + anchorNode = selection.anchorNode, + firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode), + pluginsRender = firstLevelBlock.childNodes[0]; - }; + if (!editor.core.isDomNode(anchorNode)) { + anchorNode = anchorNode.parentNode; + } - caret.position = { + var isFirstNode = anchorNode === pluginsRender.childNodes[0], + isOffsetZero = anchorOffset === 0; - atStart : function () { + return isFirstNode && isOffsetZero; + }, - var selection = window.getSelection(), - anchorOffset = selection.anchorOffset, - anchorNode = selection.anchorNode, - firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode), - pluginsRender = firstLevelBlock.childNodes[0]; + atTheEnd : function () { + var selection = window.getSelection(), + anchorOffset = selection.anchorOffset, + anchorNode = selection.anchorNode; - if (!editor.core.isDomNode(anchorNode)) { - - anchorNode = anchorNode.parentNode; - - } - - var isFirstNode = anchorNode === pluginsRender.childNodes[0], - isOffsetZero = anchorOffset === 0; - - return isFirstNode && isOffsetZero; - - }, - - atTheEnd : function () { - - var selection = window.getSelection(), - anchorOffset = selection.anchorOffset, - anchorNode = selection.anchorNode; - - /** Caret is at the end of input */ - return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length; - - } - }; + /** Caret is at the end of input */ + return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length; + } + }; - /** + /** * Inserts node at the caret location * @param {HTMLElement|DocumentFragment} node */ - caret.insertNode = function (node) { + caret.insertNode = function (node) { + var selection, range, + lastNode = node; - var selection, range, - lastNode = node; + if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) { + lastNode = node.lastChild; + } - if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) { + selection = window.getSelection(); - lastNode = node.lastChild; + range = selection.getRangeAt(0); + range.deleteContents(); - } + range.insertNode(node); - selection = window.getSelection(); + range.setStartAfter(lastNode); + range.collapse(true); - range = selection.getRangeAt(0); - range.deleteContents(); - - range.insertNode(node); - - range.setStartAfter(lastNode); - range.collapse(true); - - selection.removeAllRanges(); - selection.addRange(range); - - - }; - - return caret; + selection.removeAllRanges(); + selection.addRange(range); + }; + return caret; })({}); \ No newline at end of file diff --git a/src/components/modules/_content.js b/src/components/modules/_content.js index 6623ac8f..10ff5eb2 100644 --- a/src/components/modules/_content.js +++ b/src/components/modules/_content.js @@ -12,102 +12,87 @@ import $ from '../dom'; module.exports = class Content { - - /** + /** * Module key name * @returns {string} */ - static get name() { + static get name() { + return 'Content'; + } - return 'Content'; - - } - - /** + /** * @constructor * * @param {EditorConfig} config */ - constructor(config) { + constructor(config) { + this.config = config; + this.Editor = null; - this.config = config; - this.Editor = null; + this.CSS = { + block: 'ce-block', + content: 'ce-block__content', + stretched: 'ce-block--stretched', + highlighted: 'ce-block--highlighted', + }; - this.CSS = { - block: 'ce-block', - content: 'ce-block__content', - stretched: 'ce-block--stretched', - highlighted: 'ce-block--highlighted', - }; + this._currentNode = null; + this._currentIndex = 0; + } - this._currentNode = null; - this._currentIndex = 0; - - } - - /** + /** * Editor modules setter * @param {object} Editor */ - set state(Editor) { + set state(Editor) { + this.Editor = Editor; + } - this.Editor = Editor; - - } - - /** + /** * Get current working node * * @returns {null|HTMLElement} */ - get currentNode() { + get currentNode() { + return this._currentNode; + } - return this._currentNode; - - } - - /** + /** * Set working node. Working node should be first level block, so we find it before set one to _currentNode property * * @param {HTMLElement} node */ - set currentNode(node) { + set currentNode(node) { + let firstLevelBlock = this.getFirstLevelBlock(node); - let firstLevelBlock = this.getFirstLevelBlock(node); - - this._currentNode = firstLevelBlock; - - } + this._currentNode = firstLevelBlock; + } - /** + /** * @private * @param pluginHTML * @param {Boolean} isStretched - make stretched block or not * * @description adds necessary information to wrap new created block by first-level holder */ - composeBlock_(pluginHTML, isStretched = false) { + composeBlock_(pluginHTML, isStretched = false) { + let block = $.make('DIV', this.CSS.block), + blockContent = $.make('DIV', this.CSS.content); - let block = $.make('DIV', this.CSS.block), - blockContent = $.make('DIV', this.CSS.content); + blockContent.appendChild(pluginHTML); + block.appendChild(blockContent); - blockContent.appendChild(pluginHTML); - block.appendChild(blockContent); + if (isStretched) { + blockContent.classList.add(this.CSS.stretched); + } - if (isStretched) { + block.dataset.toolId = this._currentIndex++; - blockContent.classList.add(this.CSS.stretched); + return block; + }; - } - - block.dataset.toolId = this._currentIndex++; - - return block; - - }; - - /** + /** * Finds first-level block * @description looks for first-level block. * gets parent while node is not first-level @@ -116,33 +101,23 @@ module.exports = class Content { * @protected * */ - getFirstLevelBlock(node) { + getFirstLevelBlock(node) { + if (!$.isElement(node)) { + node = node.parentNode; + } - if (!$.isElement(node)) { + if (node === this.Editor.ui.nodes.redactor || node === document.body) { + return null; + } else { + while(node.classList && !node.classList.contains(this.CSS.block)) { + node = node.parentNode; + } - node = node.parentNode; + return node; + } + }; - } - - if (node === this.Editor.ui.nodes.redactor || node === document.body) { - - return null; - - } else { - - while(node.classList && !node.classList.contains(this.CSS.block)) { - - node = node.parentNode; - - } - - return node; - - } - - }; - - /** + /** * Insert new block to working area * * @param {HTMLElement} tool @@ -150,32 +125,25 @@ module.exports = class Content { * @returns {Number} tool index * */ - insertBlock(tool) { + insertBlock(tool) { + let newBlock = this.composeBlock_(tool); - let newBlock = this.composeBlock_(tool); - - if (this.currentNode) { - - this.currentNode.insertAdjacentElement('afterend', newBlock); - - } else { - - /** + if (this.currentNode) { + this.currentNode.insertAdjacentElement('afterend', newBlock); + } else { + /** * If redactor is empty, append as first child */ - this.Editor.ui.nodes.redactor.appendChild(newBlock); - - } - - /** - * Set new node as current - */ - this.currentNode = newBlock; - - return newBlock.dataset.toolId; - + this.Editor.ui.nodes.redactor.appendChild(newBlock); } + /** + * Set new node as current + */ + this.currentNode = newBlock; + + return newBlock.dataset.toolId; + } }; // module.exports = (function (content) { diff --git a/src/components/modules/_destroyer.js b/src/components/modules/_destroyer.js index 989f9478..c168f3fb 100644 --- a/src/components/modules/_destroyer.js +++ b/src/components/modules/_destroyer.js @@ -6,49 +6,34 @@ */ module.exports = function (destroyer) { + let editor = codex.editor; - let editor = codex.editor; + destroyer.removeNodes = function () { + editor.nodes.wrapper.remove(); + editor.nodes.notifications.remove(); + }; - destroyer.removeNodes = function () { + destroyer.destroyPlugins = function () { + for (var tool in editor.tools) { + if (typeof editor.tools[tool].destroy === 'function') { + editor.tools[tool].destroy(); + } + } + }; - editor.nodes.wrapper.remove(); - editor.nodes.notifications.remove(); + destroyer.destroyScripts = function () { + var scripts = document.getElementsByTagName('SCRIPT'); - }; - - destroyer.destroyPlugins = function () { - - for (var tool in editor.tools) { - - if (typeof editor.tools[tool].destroy === 'function') { - - editor.tools[tool].destroy(); - - } - - } - - }; - - destroyer.destroyScripts = function () { - - var scripts = document.getElementsByTagName('SCRIPT'); - - for (var i = 0; i < scripts.length; i++) { - - if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) { - - scripts[i].remove(); - i--; - - } - - } - - }; + for (var i = 0; i < scripts.length; i++) { + if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) { + scripts[i].remove(); + i--; + } + } + }; - /** + /** * Delete editor data from webpage. * You should send settings argument with boolean flags: * @param settings.ui- remove redactor event listeners and DOM nodes @@ -58,41 +43,28 @@ module.exports = function (destroyer) { * } * */ - destroyer.destroy = function (settings) { + destroyer.destroy = function (settings) { + if (!settings || typeof settings !== 'object') { + return; + } - if (!settings || typeof settings !== 'object') { + if (settings.ui) { + destroyer.removeNodes(); + editor.listeners.removeAll(); + } - return; + if (settings.scripts) { + destroyer.destroyScripts(); + } - } + if (settings.plugins) { + destroyer.destroyPlugins(); + } - if (settings.ui) { - - destroyer.removeNodes(); - editor.listeners.removeAll(); - - } - - if (settings.scripts) { - - destroyer.destroyScripts(); - - } - - if (settings.plugins) { - - destroyer.destroyPlugins(); - - } - - if (settings.ui && settings.scripts && settings.core) { - - delete codex.editor; - - } - - }; - - return destroyer; + if (settings.ui && settings.scripts && settings.core) { + delete codex.editor; + } + }; + return destroyer; }({}); \ No newline at end of file diff --git a/src/components/modules/_notifications.js b/src/components/modules/_notifications.js index ffeda9b8..1746ae6f 100644 --- a/src/components/modules/_notifications.js +++ b/src/components/modules/_notifications.js @@ -6,55 +6,44 @@ */ module.exports = (function (notifications) { + let editor = codex.editor; - let editor = codex.editor; + var queue = []; - var queue = []; + var addToQueue = function (settings) { + queue.push(settings); - var addToQueue = function (settings) { + var index = 0; - queue.push(settings); + while ( index < queue.length && queue.length > 5) { + if (queue[index].type == 'confirm' || queue[index].type == 'prompt') { + index++; + continue; + } - var index = 0; + queue[index].close(); + queue.splice(index, 1); + } + }; - while ( index < queue.length && queue.length > 5) { + notifications.createHolder = function () { + var holder = editor.draw.node('DIV', 'cdx-notifications-block'); - if (queue[index].type == 'confirm' || queue[index].type == 'prompt') { + editor.nodes.notifications = document.body.appendChild(holder); - index++; - continue; - - } - - queue[index].close(); - queue.splice(index, 1); - - } - - }; - - notifications.createHolder = function () { - - var holder = editor.draw.node('DIV', 'cdx-notifications-block'); - - editor.nodes.notifications = document.body.appendChild(holder); - - return holder; - - }; + return holder; + }; - /** + /** * Error notificator. Shows block with message * @protected */ - notifications.errorThrown = function (errorMsg, event) { + notifications.errorThrown = function (errorMsg, event) { + editor.notifications.notification({message: 'This action is not available currently', type: event.type}); + }; - editor.notifications.notification({message: 'This action is not available currently', type: event.type}); - - }; - - /** + /** * * Appends notification * @@ -70,162 +59,129 @@ module.exports = (function (notifications) { * * @param settings */ - notifications.notification = function (constructorSettings) { + notifications.notification = function (constructorSettings) { + /** Private vars and methods */ + var notification = null, + cancel = null, + type = null, + confirm = null, + inputField = null; - /** Private vars and methods */ - var notification = null, - cancel = null, - type = null, - confirm = null, - inputField = null; + var confirmHandler = function () { + close(); - var confirmHandler = function () { + if (typeof confirm !== 'function' ) { + return; + } - close(); + if (type == 'prompt') { + confirm(inputField.value); + return; + } - if (typeof confirm !== 'function' ) { + confirm(); + }; - return; + var cancelHandler = function () { + close(); - } + if (typeof cancel !== 'function' ) { + return; + } - if (type == 'prompt') { - - confirm(inputField.value); - return; - - } - - confirm(); - - }; - - var cancelHandler = function () { - - close(); - - if (typeof cancel !== 'function' ) { - - return; - - } - - cancel(); - - }; + cancel(); + }; - /** Public methods */ - function create(settings) { + /** Public methods */ + function create(settings) { + if (!(settings && settings.message)) { + editor.core.log('Can\'t create notification. Message is missed'); + return; + } - if (!(settings && settings.message)) { + settings.type = settings.type || 'alert'; + settings.time = settings.time*1000 || 10000; - editor.core.log('Can\'t create notification. Message is missed'); - return; + var wrapper = editor.draw.node('DIV', 'cdx-notification'), + message = editor.draw.node('DIV', 'cdx-notification__message'), + input = editor.draw.node('INPUT', 'cdx-notification__input'), + okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'), + cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn'); - } + message.textContent = settings.message; + okBtn.textContent = settings.okMsg || 'ОК'; + cancelBtn.textContent = settings.cancelMsg || 'Отмена'; - settings.type = settings.type || 'alert'; - settings.time = settings.time*1000 || 10000; + editor.listeners.add(okBtn, 'click', confirmHandler); + editor.listeners.add(cancelBtn, 'click', cancelHandler); - var wrapper = editor.draw.node('DIV', 'cdx-notification'), - message = editor.draw.node('DIV', 'cdx-notification__message'), - input = editor.draw.node('INPUT', 'cdx-notification__input'), - okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'), - cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn'); + wrapper.appendChild(message); - message.textContent = settings.message; - okBtn.textContent = settings.okMsg || 'ОК'; - cancelBtn.textContent = settings.cancelMsg || 'Отмена'; + if (settings.type == 'prompt') { + wrapper.appendChild(input); + } - editor.listeners.add(okBtn, 'click', confirmHandler); - editor.listeners.add(cancelBtn, 'click', cancelHandler); + wrapper.appendChild(okBtn); - wrapper.appendChild(message); + if (settings.type == 'prompt' || settings.type == 'confirm') { + wrapper.appendChild(cancelBtn); + } - if (settings.type == 'prompt') { + wrapper.classList.add('cdx-notification-' + settings.type); + wrapper.dataset.type = settings.type; - wrapper.appendChild(input); + notification = wrapper; + type = settings.type; + confirm = settings.confirm; + cancel = settings.cancel; + inputField = input; - } + if (settings.type != 'prompt' && settings.type != 'confirm') { + window.setTimeout(close, settings.time); + } + }; - wrapper.appendChild(okBtn); - - if (settings.type == 'prompt' || settings.type == 'confirm') { - - wrapper.appendChild(cancelBtn); - - } - - wrapper.classList.add('cdx-notification-' + settings.type); - wrapper.dataset.type = settings.type; - - notification = wrapper; - type = settings.type; - confirm = settings.confirm; - cancel = settings.cancel; - inputField = input; - - if (settings.type != 'prompt' && settings.type != 'confirm') { - - window.setTimeout(close, settings.time); - - } - - }; - - /** + /** * Show notification block */ - function send() { + function send() { + editor.nodes.notifications.appendChild(notification); + inputField.focus(); - editor.nodes.notifications.appendChild(notification); - inputField.focus(); + editor.nodes.notifications.classList.add('cdx-notification__notification-appending'); - editor.nodes.notifications.classList.add('cdx-notification__notification-appending'); + window.setTimeout(function () { + editor.nodes.notifications.classList.remove('cdx-notification__notification-appending'); + }, 100); - window.setTimeout(function () { + addToQueue({type: type, close: close}); + }; - editor.nodes.notifications.classList.remove('cdx-notification__notification-appending'); - - }, 100); - - addToQueue({type: type, close: close}); - - }; - - /** + /** * Remove notification block */ - function close() { - - notification.remove(); - - }; - - - if (constructorSettings) { - - create(constructorSettings); - send(); - - } - - return { - create: create, - send: send, - close: close - }; - + function close() { + notification.remove(); }; - notifications.clear = function () { - editor.nodes.notifications.innerHTML = ''; - queue = []; + if (constructorSettings) { + create(constructorSettings); + send(); + } + return { + create: create, + send: send, + close: close }; + }; - return notifications; + notifications.clear = function () { + editor.nodes.notifications.innerHTML = ''; + queue = []; + }; + return notifications; })({}); \ No newline at end of file diff --git a/src/components/modules/_parser.js b/src/components/modules/_parser.js index 70debc9c..6eefb459 100644 --- a/src/components/modules/_parser.js +++ b/src/components/modules/_parser.js @@ -6,31 +6,25 @@ */ module.exports = (function (parser) { + let editor = codex.editor; - let editor = codex.editor; + /** inserting text */ + parser.insertPastedContent = function (blockType, tag) { + editor.content.insertBlock({ + type : blockType.type, + block : blockType.render({ + text : tag.innerHTML + }) + }); + }; - /** inserting text */ - parser.insertPastedContent = function (blockType, tag) { - - editor.content.insertBlock({ - type : blockType.type, - block : blockType.render({ - text : tag.innerHTML - }) - }); - - }; - - /** + /** * Check DOM node for display style: separated block or child-view */ - parser.isFirstLevelBlock = function (node) { - - return node.nodeType == editor.core.nodeTypes.TAG && + parser.isFirstLevelBlock = function (node) { + return node.nodeType == editor.core.nodeTypes.TAG && node.classList.contains(editor.ui.className.BLOCK_CLASSNAME); + }; - }; - - return parser; - + return parser; })({}); diff --git a/src/components/modules/_paste.js b/src/components/modules/_paste.js index ae810185..61fc63de 100644 --- a/src/components/modules/_paste.js +++ b/src/components/modules/_paste.js @@ -6,106 +6,82 @@ */ module.exports = function (paste) { + let editor = codex.editor; - let editor = codex.editor; + var patterns = []; - var patterns = []; + paste.prepare = function () { + var tools = editor.tools; - paste.prepare = function () { + for (var tool in tools) { + if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) { + continue; + } - var tools = editor.tools; + tools[tool].renderOnPastePatterns.map(function (pattern) { + patterns.push(pattern); + }); + } - for (var tool in tools) { + return Promise.resolve(); + }; - if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) { - - continue; - - } - - tools[tool].renderOnPastePatterns.map(function (pattern) { - - - patterns.push(pattern); - - }); - - } - - return Promise.resolve(); - - }; - - /** + /** * Saves data * @param event */ - paste.pasted = function (event) { + paste.pasted = function (event) { + var clipBoardData = event.clipboardData || window.clipboardData, + content = clipBoardData.getData('Text'); - var clipBoardData = event.clipboardData || window.clipboardData, - content = clipBoardData.getData('Text'); + var result = analize(content); - var result = analize(content); + if (result) { + event.preventDefault(); + event.stopImmediatePropagation(); + } - if (result) { + return result; + }; - event.preventDefault(); - event.stopImmediatePropagation(); - - } - - return result; - - }; - - /** + /** * Analizes pated string and calls necessary method */ - var analize = function (string) { + var analize = function (string) { + var result = false, + content = editor.content.currentNode, + plugin = content.dataset.tool; - var result = false, - content = editor.content.currentNode, - plugin = content.dataset.tool; + patterns.map( function (pattern) { + var execArray = pattern.regex.exec(string), + match = execArray && execArray[0]; - patterns.map( function (pattern) { + if ( match && match === string.trim()) { + /** current block is not empty */ + if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) { + pasteToNewBlock_(); + } - var execArray = pattern.regex.exec(string), - match = execArray && execArray[0]; + pattern.callback(string, pattern); + result = true; + } + }); - if ( match && match === string.trim()) { + return result; + }; - /** current block is not empty */ - if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) { + var pasteToNewBlock_ = function () { + /** Create new initial block */ + editor.content.insertBlock({ - pasteToNewBlock_(); + type : editor.settings.initialBlockPlugin, + block : editor.tools[editor.settings.initialBlockPlugin].render({ + text : '' + }) - } - - pattern.callback(string, pattern); - result = true; - - } - - }); - - return result; - - }; - - var pasteToNewBlock_ = function () { - - /** Create new initial block */ - editor.content.insertBlock({ - - type : editor.settings.initialBlockPlugin, - block : editor.tools[editor.settings.initialBlockPlugin].render({ - text : '' - }) - - }, false); - - }; + }, false); + }; /** * This method prevents default behaviour. @@ -117,162 +93,129 @@ module.exports = function (paste) { * Firstly, we need to memorize the caret position. We can do that by getting the range of selection. * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node */ - paste.blockPasteCallback = function (event) { + paste.blockPasteCallback = function (event) { + if (!needsToHandlePasteEvent(event.target)) { + return; + } + /** Prevent default behaviour */ + event.preventDefault(); - if (!needsToHandlePasteEvent(event.target)) { + /** get html pasted data - dirty data */ + var htmlData = event.clipboardData.getData('text/html'), + plainData = event.clipboardData.getData('text/plain'); - return; + /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/ + var paragraphs = editor.draw.node('DIV', '', {}), + cleanData, + wrappedData; - } + /** Create fragment, that we paste to range after proccesing */ + cleanData = editor.sanitizer.clean(htmlData); - /** Prevent default behaviour */ - event.preventDefault(); - - /** get html pasted data - dirty data */ - var htmlData = event.clipboardData.getData('text/html'), - plainData = event.clipboardData.getData('text/plain'); - - /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/ - var paragraphs = editor.draw.node('DIV', '', {}), - cleanData, - wrappedData; - - /** Create fragment, that we paste to range after proccesing */ - cleanData = editor.sanitizer.clean(htmlData); - - /** + /** * We wrap pasted text with

      tags to split it logically * @type {string} */ - wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData); - paragraphs.innerHTML = wrappedData; - - /** - * If there only one paragraph, just insert in at the caret location - */ - if (paragraphs.childNodes.length == 1) { - - emulateUserAgentBehaviour(paragraphs.firstChild); - return; - - } - - insertPastedParagraphs(paragraphs.childNodes); - - }; + wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData); + paragraphs.innerHTML = wrappedData; /** + * If there only one paragraph, just insert in at the caret location + */ + if (paragraphs.childNodes.length == 1) { + emulateUserAgentBehaviour(paragraphs.firstChild); + return; + } + + insertPastedParagraphs(paragraphs.childNodes); + }; + + /** * Checks if we should handle paste event on block * @param block * * @return {boolean} */ - var needsToHandlePasteEvent = function (block) { + var needsToHandlePasteEvent = function (block) { + /** If area is input or textarea then allow default behaviour */ + if ( editor.core.isNativeInput(block) ) { + return false; + } - /** If area is input or textarea then allow default behaviour */ - if ( editor.core.isNativeInput(block) ) { + var editableParent = editor.content.getEditableParent(block); - return false; + /** Allow paste when event target placed in Editable element */ + if (!editableParent) { + return false; + } - } - - var editableParent = editor.content.getEditableParent(block); - - /** Allow paste when event target placed in Editable element */ - if (!editableParent) { - - return false; - - } - - return true; - - }; + return true; + }; /** * Inserts new initial plugin blocks with data in paragraphs * * @param {Array} paragraphs - array of paragraphs (

      ) whit content, that should be inserted */ - var insertPastedParagraphs = function (paragraphs) { - - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin, - currentNode = editor.content.currentNode; + var insertPastedParagraphs = function (paragraphs) { + var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin, + currentNode = editor.content.currentNode; - paragraphs.forEach(function (paragraph) { + paragraphs.forEach(function (paragraph) { + /** Don't allow empty paragraphs */ + if (editor.core.isBlockEmpty(paragraph)) { + return; + } - /** Don't allow empty paragraphs */ - if (editor.core.isBlockEmpty(paragraph)) { + editor.content.insertBlock({ + type : NEW_BLOCK_TYPE, + block : editor.tools[NEW_BLOCK_TYPE].render({ + text : paragraph.innerHTML + }) + }); - return; + editor.caret.inputIndex++; + }); - } - - editor.content.insertBlock({ - type : NEW_BLOCK_TYPE, - block : editor.tools[NEW_BLOCK_TYPE].render({ - text : paragraph.innerHTML - }) - }); - - editor.caret.inputIndex++; - - }); - - editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1); + editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1); - /** + /** * If there was no data in working node, remove it */ - if (editor.core.isBlockEmpty(currentNode)) { - - currentNode.remove(); - editor.ui.saveInputs(); - - } - - - }; + if (editor.core.isBlockEmpty(currentNode)) { + currentNode.remove(); + editor.ui.saveInputs(); + } + }; /** * Inserts node content at the caret position * * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location */ - var emulateUserAgentBehaviour = function (node) { + var emulateUserAgentBehaviour = function (node) { + var newNode; - var newNode; - - if (node.childElementCount) { - - newNode = document.createDocumentFragment(); - - node.childNodes.forEach(function (current) { - - if (!editor.core.isDomNode(current) && current.data.trim() === '') { - - return; - - } - - newNode.appendChild(current.cloneNode(true)); - - }); - - } else { - - newNode = document.createTextNode(node.textContent); + if (node.childElementCount) { + newNode = document.createDocumentFragment(); + node.childNodes.forEach(function (current) { + if (!editor.core.isDomNode(current) && current.data.trim() === '') { + return; } - editor.caret.insertNode(newNode); + newNode.appendChild(current.cloneNode(true)); + }); + } else { + newNode = document.createTextNode(node.textContent); + } - }; + editor.caret.insertNode(newNode); + }; - return paste; - + return paste; }({}); \ No newline at end of file diff --git a/src/components/modules/_transport.js b/src/components/modules/_transport.js index 7f659e37..ba29e2b6 100644 --- a/src/components/modules/_transport.js +++ b/src/components/modules/_transport.js @@ -7,90 +7,77 @@ */ module.exports = (function (transport) { - - let editor = codex.editor; + let editor = codex.editor; - /** + /** * @private {Object} current XmlHttpRequest instance */ - var currentRequest = null; + var currentRequest = null; - /** + /** * @type {null} | {DOMElement} input - keeps input element in memory */ - transport.input = null; + transport.input = null; - /** + /** * @property {Object} arguments - keep plugin settings and defined callbacks */ - transport.arguments = null; + transport.arguments = null; - /** + /** * Prepares input element where will be files */ - transport.prepare = function () { + transport.prepare = function () { + let input = editor.draw.node( 'INPUT', '', { type : 'file' } ); - let input = editor.draw.node( 'INPUT', '', { type : 'file' } ); + editor.listeners.add(input, 'change', editor.transport.fileSelected); + editor.transport.input = input; + }; - editor.listeners.add(input, 'change', editor.transport.fileSelected); - editor.transport.input = input; + /** Clear input when files is uploaded */ + transport.clearInput = function () { + /** Remove old input */ + transport.input = null; - }; + /** Prepare new one */ + transport.prepare(); + }; - /** Clear input when files is uploaded */ - transport.clearInput = function () { - - /** Remove old input */ - transport.input = null; - - /** Prepare new one */ - transport.prepare(); - - }; - - /** + /** * Callback for file selection * @param {Event} event */ - transport.fileSelected = function () { + transport.fileSelected = function () { + var input = this, + i, + files = input.files, + formData = new FormData(); - var input = this, - i, - files = input.files, - formData = new FormData(); + if (editor.transport.arguments.multiple === true) { + for ( i = 0; i < files.length; i++) { + formData.append('files[]', files[i], files[i].name); + } + } else { + formData.append('files', files[0], files[0].name); + } - if (editor.transport.arguments.multiple === true) { + currentRequest = editor.core.ajax({ + type : 'POST', + data : formData, + url : editor.transport.arguments.url, + beforeSend : editor.transport.arguments.beforeSend, + success : editor.transport.arguments.success, + error : editor.transport.arguments.error, + progress : editor.transport.arguments.progress + }); - for ( i = 0; i < files.length; i++) { + /** Clear input */ + transport.clearInput(); + }; - formData.append('files[]', files[i], files[i].name); - - } - - } else { - - formData.append('files', files[0], files[0].name); - - } - - currentRequest = editor.core.ajax({ - type : 'POST', - data : formData, - url : editor.transport.arguments.url, - beforeSend : editor.transport.arguments.beforeSend, - success : editor.transport.arguments.success, - error : editor.transport.arguments.error, - progress : editor.transport.arguments.progress - }); - - /** Clear input */ - transport.clearInput(); - - }; - - /** + /** * Use plugin callbacks * @protected * @@ -103,34 +90,25 @@ module.exports = (function (transport) { * @param {Boolean} args.multiple - allow select several files * @param {String} args.accept - adds accept attribute */ - transport.selectAndUpload = function (args) { + transport.selectAndUpload = function (args) { + transport.arguments = args; - transport.arguments = args; + if ( args.multiple === true) { + transport.input.setAttribute('multiple', 'multiple'); + } - if ( args.multiple === true) { + if ( args.accept ) { + transport.input.setAttribute('accept', args.accept); + } - transport.input.setAttribute('multiple', 'multiple'); + transport.input.click(); + }; - } + transport.abort = function () { + currentRequest.abort(); - if ( args.accept ) { - - transport.input.setAttribute('accept', args.accept); - - } - - transport.input.click(); - - }; - - transport.abort = function () { - - currentRequest.abort(); - - currentRequest = null; - - }; - - return transport; + currentRequest = null; + }; + return transport; })({}); \ No newline at end of file diff --git a/src/components/modules/toolbar/inline.js b/src/components/modules/toolbar/inline.js index e785f0c1..fb50e8dd 100644 --- a/src/components/modules/toolbar/inline.js +++ b/src/components/modules/toolbar/inline.js @@ -9,148 +9,129 @@ */ module.exports = (function (inline) { + let editor = codex.editor; - let editor = codex.editor; + inline.buttonsOpened = null; + inline.actionsOpened = null; + inline.wrappersOffset = null; - inline.buttonsOpened = null; - inline.actionsOpened = null; - inline.wrappersOffset = null; - - /** + /** * saving selection that need for execCommand for styling * */ - inline.storedSelection = null; + inline.storedSelection = null; - /** + /** * @protected * * Open inline toobar */ - inline.show = function () { - - var currentNode = editor.content.currentNode, - tool = currentNode.dataset.tool, - plugin; - - /** - * tool allowed to open inline toolbar - */ - plugin = editor.tools[tool]; - - if (!plugin.showInlineToolbar) - return; - - var selectedText = inline.getSelectionText(), - toolbar = editor.nodes.inlineToolbar.wrapper; - - if (selectedText.length > 0) { - - /** Move toolbar and open */ - editor.toolbar.inline.move(); - - /** Open inline toolbar */ - toolbar.classList.add('opened'); - - /** show buttons of inline toolbar */ - editor.toolbar.inline.showButtons(); - - } - - }; + inline.show = function () { + var currentNode = editor.content.currentNode, + tool = currentNode.dataset.tool, + plugin; /** + * tool allowed to open inline toolbar + */ + plugin = editor.tools[tool]; + + if (!plugin.showInlineToolbar) + return; + + var selectedText = inline.getSelectionText(), + toolbar = editor.nodes.inlineToolbar.wrapper; + + if (selectedText.length > 0) { + /** Move toolbar and open */ + editor.toolbar.inline.move(); + + /** Open inline toolbar */ + toolbar.classList.add('opened'); + + /** show buttons of inline toolbar */ + editor.toolbar.inline.showButtons(); + } + }; + + /** * @protected * * Closes inline toolbar */ - inline.close = function () { + inline.close = function () { + var toolbar = editor.nodes.inlineToolbar.wrapper; - var toolbar = editor.nodes.inlineToolbar.wrapper; + toolbar.classList.remove('opened'); + }; - toolbar.classList.remove('opened'); - - }; - - /** + /** * @private * * Moving toolbar */ - inline.move = function () { + inline.move = function () { + if (!this.wrappersOffset) { + this.wrappersOffset = this.getWrappersOffset(); + } - if (!this.wrappersOffset) { + var coords = this.getSelectionCoords(), + defaultOffset = 0, + toolbar = editor.nodes.inlineToolbar.wrapper, + newCoordinateX, + newCoordinateY; - this.wrappersOffset = this.getWrappersOffset(); + if (toolbar.offsetHeight === 0) { + defaultOffset = 40; + } - } + newCoordinateX = coords.x - this.wrappersOffset.left; + newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight; - var coords = this.getSelectionCoords(), - defaultOffset = 0, - toolbar = editor.nodes.inlineToolbar.wrapper, - newCoordinateX, - newCoordinateY; + toolbar.style.transform = `translate3D(${Math.floor(newCoordinateX)}px, ${Math.floor(newCoordinateY)}px, 0)`; - if (toolbar.offsetHeight === 0) { + /** Close everything */ + editor.toolbar.inline.closeButtons(); + editor.toolbar.inline.closeAction(); + }; - defaultOffset = 40; - - } - - newCoordinateX = coords.x - this.wrappersOffset.left; - newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight; - - toolbar.style.transform = `translate3D(${Math.floor(newCoordinateX)}px, ${Math.floor(newCoordinateY)}px, 0)`; - - /** Close everything */ - editor.toolbar.inline.closeButtons(); - editor.toolbar.inline.closeAction(); - - }; - - /** + /** * @private * * Tool Clicked */ - inline.toolClicked = function (event, type) { - - /** + inline.toolClicked = function (event, type) { + /** * For simple tools we use default browser function * For more complicated tools, we should write our own behavior */ - switch (type) { + switch (type) { + case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break; + default : editor.toolbar.inline.defaultToolAction(type); break; + } - case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break; - default : editor.toolbar.inline.defaultToolAction(type); break; - - } - - /** + /** * highlight buttons * after making some action */ - editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); + editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); + }; - }; - - /** + /** * @private * * Saving wrappers offset in DOM */ - inline.getWrappersOffset = function () { + inline.getWrappersOffset = function () { + var wrapper = editor.nodes.wrapper, + offset = this.getOffset(wrapper); - var wrapper = editor.nodes.wrapper, - offset = this.getOffset(wrapper); + this.wrappersOffset = offset; + return offset; + }; - this.wrappersOffset = offset; - return offset; - - }; - - /** + /** * @private * * Calculates offset of DOM element @@ -158,286 +139,233 @@ module.exports = (function (inline) { * @param el * @returns {{top: number, left: number}} */ - inline.getOffset = function ( el ) { + inline.getOffset = function ( el ) { + var _x = 0; + var _y = 0; - var _x = 0; - var _y = 0; + while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { + _x += (el.offsetLeft + el.clientLeft); + _y += (el.offsetTop + el.clientTop); + el = el.offsetParent; + } + return { top: _y, left: _x }; + }; - while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) { - - _x += (el.offsetLeft + el.clientLeft); - _y += (el.offsetTop + el.clientTop); - el = el.offsetParent; - - } - return { top: _y, left: _x }; - - }; - - /** + /** * @private * * Calculates position of selected text * @returns {{x: number, y: number}} */ - inline.getSelectionCoords = function () { + inline.getSelectionCoords = function () { + var sel = document.selection, range; + var x = 0, y = 0; - var sel = document.selection, range; - var x = 0, y = 0; + if (sel) { + if (sel.type != 'Control') { + range = sel.createRange(); + range.collapse(true); + x = range.boundingLeft; + y = range.boundingTop; + } + } else if (window.getSelection) { + sel = window.getSelection(); - if (sel) { + if (sel.rangeCount) { + range = sel.getRangeAt(0).cloneRange(); + if (range.getClientRects) { + range.collapse(true); + var rect = range.getClientRects()[0]; - if (sel.type != 'Control') { - - range = sel.createRange(); - range.collapse(true); - x = range.boundingLeft; - y = range.boundingTop; - - } - - } else if (window.getSelection) { - - sel = window.getSelection(); - - if (sel.rangeCount) { - - range = sel.getRangeAt(0).cloneRange(); - if (range.getClientRects) { - - range.collapse(true); - var rect = range.getClientRects()[0]; - - if (!rect) { - - return; - - } - - x = rect.left; - y = rect.top; - - } - - } + if (!rect) { + return; + } + x = rect.left; + y = rect.top; } - return { x: x, y: y }; + } + } + return { x: x, y: y }; + }; - }; - - /** + /** * @private * * Returns selected text as String * @returns {string} */ - inline.getSelectionText = function () { + inline.getSelectionText = function () { + var selectedText = ''; - var selectedText = ''; + // all modern browsers and IE9+ + if (window.getSelection) { + selectedText = window.getSelection().toString(); + } - // all modern browsers and IE9+ - if (window.getSelection) { + return selectedText; + }; - selectedText = window.getSelection().toString(); + /** Opens buttons block */ + inline.showButtons = function () { + var buttons = editor.nodes.inlineToolbar.buttons; - } + buttons.classList.add('opened'); - return selectedText; + editor.toolbar.inline.buttonsOpened = true; - }; + /** highlight buttons */ + editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); + }; - /** Opens buttons block */ - inline.showButtons = function () { + /** Makes buttons disappear */ + inline.closeButtons = function () { + var buttons = editor.nodes.inlineToolbar.buttons; - var buttons = editor.nodes.inlineToolbar.buttons; + buttons.classList.remove('opened'); - buttons.classList.add('opened'); + editor.toolbar.inline.buttonsOpened = false; + }; - editor.toolbar.inline.buttonsOpened = true; + /** Open buttons defined action if exist */ + inline.showActions = function () { + var action = editor.nodes.inlineToolbar.actions; - /** highlight buttons */ - editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); + action.classList.add('opened'); - }; + editor.toolbar.inline.actionsOpened = true; + }; - /** Makes buttons disappear */ - inline.closeButtons = function () { + /** Close actions block */ + inline.closeAction = function () { + var action = editor.nodes.inlineToolbar.actions; - var buttons = editor.nodes.inlineToolbar.buttons; - - buttons.classList.remove('opened'); - - editor.toolbar.inline.buttonsOpened = false; - - }; - - /** Open buttons defined action if exist */ - inline.showActions = function () { - - var action = editor.nodes.inlineToolbar.actions; - - action.classList.add('opened'); - - editor.toolbar.inline.actionsOpened = true; - - }; - - /** Close actions block */ - inline.closeAction = function () { - - var action = editor.nodes.inlineToolbar.actions; - - action.innerHTML = ''; - action.classList.remove('opened'); - editor.toolbar.inline.actionsOpened = false; - - }; + action.innerHTML = ''; + action.classList.remove('opened'); + editor.toolbar.inline.actionsOpened = false; + }; - /** + /** * Callback for keydowns in inline toolbar "Insert link..." input */ - let inlineToolbarAnchorInputKeydown_ = function (event) { + let inlineToolbarAnchorInputKeydown_ = function (event) { + if (event.keyCode != editor.core.keys.ENTER) { + return; + } - if (event.keyCode != editor.core.keys.ENTER) { + let editable = editor.content.currentNode, + storedSelection = editor.toolbar.inline.storedSelection; - return; + editor.toolbar.inline.restoreSelection(editable, storedSelection); + editor.toolbar.inline.setAnchor(this.value); - } - - let editable = editor.content.currentNode, - storedSelection = editor.toolbar.inline.storedSelection; - - editor.toolbar.inline.restoreSelection(editable, storedSelection); - editor.toolbar.inline.setAnchor(this.value); - - /** + /** * Preventing events that will be able to happen */ - event.preventDefault(); - event.stopImmediatePropagation(); + event.preventDefault(); + event.stopImmediatePropagation(); - editor.toolbar.inline.clearRange(); - - }; + editor.toolbar.inline.clearRange(); + }; /** Action for link creation or for setting anchor */ - inline.createLinkAction = function (event) { + inline.createLinkAction = function (event) { + var isActive = this.isLinkActive(); - var isActive = this.isLinkActive(); + var editable = editor.content.currentNode, + storedSelection = editor.toolbar.inline.saveSelection(editable); - var editable = editor.content.currentNode, - storedSelection = editor.toolbar.inline.saveSelection(editable); + /** Save globally selection */ + editor.toolbar.inline.storedSelection = storedSelection; - /** Save globally selection */ - editor.toolbar.inline.storedSelection = storedSelection; - - if (isActive) { - - - /** + if (isActive) { + /** * Changing stored selection. if we want to remove anchor from word * we should remove anchor from whole word, not only selected part. * The solution is than we get the length of current link * Change start position to - end of selection minus length of anchor */ - editor.toolbar.inline.restoreSelection(editable, storedSelection); + editor.toolbar.inline.restoreSelection(editable, storedSelection); - editor.toolbar.inline.defaultToolAction('unlink'); + editor.toolbar.inline.defaultToolAction('unlink'); + } else { + /** Create input and close buttons */ + var action = editor.draw.inputForLink(); - } else { + editor.nodes.inlineToolbar.actions.appendChild(action); - /** Create input and close buttons */ - var action = editor.draw.inputForLink(); + editor.toolbar.inline.closeButtons(); + editor.toolbar.inline.showActions(); - editor.nodes.inlineToolbar.actions.appendChild(action); - - editor.toolbar.inline.closeButtons(); - editor.toolbar.inline.showActions(); - - /** + /** * focus to input * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus * Prevents event after showing input and when we need to focus an input which is in unexisted form */ - action.focus(); - event.preventDefault(); + action.focus(); + event.preventDefault(); - /** Callback to link action */ - editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false); + /** Callback to link action */ + editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false); + } + }; - } + inline.isLinkActive = function () { + var isActive = false; - }; + editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) { + var dataType = tool.dataset.type; - inline.isLinkActive = function () { + if (dataType == 'link' && tool.classList.contains('hightlighted')) { + isActive = true; + } + }); - var isActive = false; + return isActive; + }; - editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) { + /** default action behavior of tool */ + inline.defaultToolAction = function (type) { + document.execCommand(type, false, null); + }; - var dataType = tool.dataset.type; - - if (dataType == 'link' && tool.classList.contains('hightlighted')) { - - isActive = true; - - } - - }); - - return isActive; - - }; - - /** default action behavior of tool */ - inline.defaultToolAction = function (type) { - - document.execCommand(type, false, null); - - }; - - /** + /** * @private * * Sets URL * * @param {String} url - URL */ - inline.setAnchor = function (url) { + inline.setAnchor = function (url) { + document.execCommand('createLink', false, url); - document.execCommand('createLink', false, url); + /** Close after URL inserting */ + editor.toolbar.inline.closeAction(); + }; - /** Close after URL inserting */ - editor.toolbar.inline.closeAction(); - - }; - - /** + /** * @private * * Saves selection */ - inline.saveSelection = function (containerEl) { + inline.saveSelection = function (containerEl) { + var range = window.getSelection().getRangeAt(0), + preSelectionRange = range.cloneRange(), + start; - var range = window.getSelection().getRangeAt(0), - preSelectionRange = range.cloneRange(), - start; + preSelectionRange.selectNodeContents(containerEl); + preSelectionRange.setEnd(range.startContainer, range.startOffset); - preSelectionRange.selectNodeContents(containerEl); - preSelectionRange.setEnd(range.startContainer, range.startOffset); - - start = preSelectionRange.toString().length; - - return { - start: start, - end: start + range.toString().length - }; + start = preSelectionRange.toString().length; + return { + start: start, + end: start + range.toString().length }; + }; - /** + /** * @private * * Sets to previous selection (Range) @@ -445,151 +373,118 @@ module.exports = (function (inline) { * @param {Element} containerEl - editable element where we restore range * @param {Object} savedSel - range basic information to restore */ - inline.restoreSelection = function (containerEl, savedSel) { + inline.restoreSelection = function (containerEl, savedSel) { + var range = document.createRange(), + charIndex = 0; - var range = document.createRange(), - charIndex = 0; + range.setStart(containerEl, 0); + range.collapse(true); - range.setStart(containerEl, 0); - range.collapse(true); + var nodeStack = [ containerEl ], + node, + foundStart = false, + stop = false, + nextCharIndex; - var nodeStack = [ containerEl ], - node, - foundStart = false, - stop = false, - nextCharIndex; - - while (!stop && (node = nodeStack.pop())) { - - if (node.nodeType == 3) { - - nextCharIndex = charIndex + node.length; - - if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) { - - range.setStart(node, savedSel.start - charIndex); - foundStart = true; - - } - if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) { - - range.setEnd(node, savedSel.end - charIndex); - stop = true; - - } - charIndex = nextCharIndex; - - } else { - - var i = node.childNodes.length; - - while (i--) { - - nodeStack.push(node.childNodes[i]); - - } - - } + while (!stop && (node = nodeStack.pop())) { + if (node.nodeType == 3) { + nextCharIndex = charIndex + node.length; + if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) { + range.setStart(node, savedSel.start - charIndex); + foundStart = true; } + if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) { + range.setEnd(node, savedSel.end - charIndex); + stop = true; + } + charIndex = nextCharIndex; + } else { + var i = node.childNodes.length; - var sel = window.getSelection(); + while (i--) { + nodeStack.push(node.childNodes[i]); + } + } + } - sel.removeAllRanges(); - sel.addRange(range); + var sel = window.getSelection(); - }; + sel.removeAllRanges(); + sel.addRange(range); + }; - /** + /** * @private * * Removes all ranges from window selection */ - inline.clearRange = function () { + inline.clearRange = function () { + var selection = window.getSelection(); - var selection = window.getSelection(); + selection.removeAllRanges(); + }; - selection.removeAllRanges(); - - }; - - /** + /** * @private * * sets or removes hightlight */ - inline.hightlight = function (tool) { + inline.hightlight = function (tool) { + var dataType = tool.dataset.type; - var dataType = tool.dataset.type; + if (document.queryCommandState(dataType)) { + editor.toolbar.inline.setButtonHighlighted(tool); + } else { + editor.toolbar.inline.removeButtonsHighLight(tool); + } - if (document.queryCommandState(dataType)) { - - editor.toolbar.inline.setButtonHighlighted(tool); - - } else { - - editor.toolbar.inline.removeButtonsHighLight(tool); - - } - - /** + /** * * hightlight for anchors */ - var selection = window.getSelection(), - tag = selection.anchorNode.parentNode; + var selection = window.getSelection(), + tag = selection.anchorNode.parentNode; - if (tag.tagName == 'A' && dataType == 'link') { + if (tag.tagName == 'A' && dataType == 'link') { + editor.toolbar.inline.setButtonHighlighted(tool); + } + }; - editor.toolbar.inline.setButtonHighlighted(tool); - - } - - }; - - /** + /** * @private * * Mark button if text is already executed */ - inline.setButtonHighlighted = function (button) { + inline.setButtonHighlighted = function (button) { + button.classList.add('hightlighted'); - button.classList.add('hightlighted'); + /** At link tool we also change icon */ + if (button.dataset.type == 'link') { + var icon = button.childNodes[0]; - /** At link tool we also change icon */ - if (button.dataset.type == 'link') { + icon.classList.remove('ce-icon-link'); + icon.classList.add('ce-icon-unlink'); + } + }; - var icon = button.childNodes[0]; - - icon.classList.remove('ce-icon-link'); - icon.classList.add('ce-icon-unlink'); - - } - - }; - - /** + /** * @private * * Removes hightlight */ - inline.removeButtonsHighLight = function (button) { + inline.removeButtonsHighLight = function (button) { + button.classList.remove('hightlighted'); - button.classList.remove('hightlighted'); + /** At link tool we also change icon */ + if (button.dataset.type == 'link') { + var icon = button.childNodes[0]; - /** At link tool we also change icon */ - if (button.dataset.type == 'link') { - - var icon = button.childNodes[0]; - - icon.classList.remove('ce-icon-unlink'); - icon.classList.add('ce-icon-link'); - - } - - }; + icon.classList.remove('ce-icon-unlink'); + icon.classList.add('ce-icon-link'); + } + }; - return inline; - + return inline; })({}); \ No newline at end of file diff --git a/src/components/modules/toolbar/settings.js b/src/components/modules/toolbar/settings.js index 307c719d..54082914 100644 --- a/src/components/modules/toolbar/settings.js +++ b/src/components/modules/toolbar/settings.js @@ -5,168 +5,136 @@ */ module.exports = (function (settings) { + let editor = codex.editor; - let editor = codex.editor; + settings.opened = false; - settings.opened = false; + settings.setting = null; + settings.actions = null; - settings.setting = null; - settings.actions = null; - - /** + /** * Append and open settings */ - settings.open = function (toolType) { - - /** + settings.open = function (toolType) { + /** * Append settings content * It's stored in tool.settings */ - if ( !editor.tools[toolType] || !editor.tools[toolType].makeSettings ) { + if ( !editor.tools[toolType] || !editor.tools[toolType].makeSettings ) { + return; + } - return; - - } - - /** + /** * Draw settings block */ - var settingsBlock = editor.tools[toolType].makeSettings(); + var settingsBlock = editor.tools[toolType].makeSettings(); - editor.nodes.pluginSettings.appendChild(settingsBlock); + editor.nodes.pluginSettings.appendChild(settingsBlock); - /** Open settings block */ - editor.nodes.blockSettings.classList.add('opened'); - this.opened = true; + /** Open settings block */ + editor.nodes.blockSettings.classList.add('opened'); + this.opened = true; + }; - }; - - /** + /** * Close and clear settings */ - settings.close = function () { + settings.close = function () { + editor.nodes.blockSettings.classList.remove('opened'); + editor.nodes.pluginSettings.innerHTML = ''; - editor.nodes.blockSettings.classList.remove('opened'); - editor.nodes.pluginSettings.innerHTML = ''; + this.opened = false; + }; - this.opened = false; - - }; - - /** + /** * @param {string} toolType - plugin type */ - settings.toggle = function ( toolType ) { + settings.toggle = function ( toolType ) { + if ( !this.opened ) { + this.open(toolType); + } else { + this.close(); + } + }; - if ( !this.opened ) { - - this.open(toolType); - - } else { - - this.close(); - - } - - }; - - /** + /** * Here we will draw buttons and add listeners to components */ - settings.makeRemoveBlockButton = function () { + settings.makeRemoveBlockButton = function () { + var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}), + settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML : '' }), + actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}), + confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }), + cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' }); - var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}), - settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML : '' }), - actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}), - confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }), - cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' }); + editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false); - editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false); + editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false); - editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false); + editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false); - editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false); + actionWrapper.appendChild(confirmAction); + actionWrapper.appendChild(cancelAction); - actionWrapper.appendChild(confirmAction); - actionWrapper.appendChild(cancelAction); + removeBlockWrapper.appendChild(settingButton); + removeBlockWrapper.appendChild(actionWrapper); - removeBlockWrapper.appendChild(settingButton); - removeBlockWrapper.appendChild(actionWrapper); + /** Save setting */ + editor.toolbar.settings.setting = settingButton; + editor.toolbar.settings.actions = actionWrapper; - /** Save setting */ - editor.toolbar.settings.setting = settingButton; - editor.toolbar.settings.actions = actionWrapper; + return removeBlockWrapper; + }; - return removeBlockWrapper; + settings.removeButtonClicked = function () { + var action = editor.toolbar.settings.actions; - }; + if (action.classList.contains('opened')) { + editor.toolbar.settings.hideRemoveActions(); + } else { + editor.toolbar.settings.showRemoveActions(); + } - settings.removeButtonClicked = function () { + editor.toolbar.toolbox.close(); + editor.toolbar.settings.close(); + }; - var action = editor.toolbar.settings.actions; + settings.cancelRemovingRequest = function () { + editor.toolbar.settings.actions.classList.remove('opened'); + }; - if (action.classList.contains('opened')) { + settings.confirmRemovingRequest = function () { + var currentBlock = editor.content.currentNode, + firstLevelBlocksCount; - editor.toolbar.settings.hideRemoveActions(); + currentBlock.remove(); - } else { + firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; - editor.toolbar.settings.showRemoveActions(); - - } - - editor.toolbar.toolbox.close(); - editor.toolbar.settings.close(); - - }; - - settings.cancelRemovingRequest = function () { - - editor.toolbar.settings.actions.classList.remove('opened'); - - }; - - settings.confirmRemovingRequest = function () { - - var currentBlock = editor.content.currentNode, - firstLevelBlocksCount; - - currentBlock.remove(); - - firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; - - /** + /** * If all blocks are removed */ - if (firstLevelBlocksCount === 0) { + if (firstLevelBlocksCount === 0) { + /** update currentNode variable */ + editor.content.currentNode = null; - /** update currentNode variable */ - editor.content.currentNode = null; + /** Inserting new empty initial block */ + editor.ui.addInitialBlock(); + } - /** Inserting new empty initial block */ - editor.ui.addInitialBlock(); + editor.ui.saveInputs(); - } + editor.toolbar.close(); + }; - editor.ui.saveInputs(); + settings.showRemoveActions = function () { + editor.toolbar.settings.actions.classList.add('opened'); + }; - editor.toolbar.close(); - - }; - - settings.showRemoveActions = function () { - - editor.toolbar.settings.actions.classList.add('opened'); - - }; - - settings.hideRemoveActions = function () { - - editor.toolbar.settings.actions.classList.remove('opened'); - - }; - - return settings; + settings.hideRemoveActions = function () { + editor.toolbar.settings.actions.classList.remove('opened'); + }; + return settings; })({}); diff --git a/src/components/modules/toolbar/toolbar.js b/src/components/modules/toolbar/toolbar.js index e59b7d68..aa0032d7 100644 --- a/src/components/modules/toolbar/toolbar.js +++ b/src/components/modules/toolbar/toolbar.js @@ -11,123 +11,95 @@ */ module.exports = (function (toolbar) { + let editor = codex.editor; - let editor = codex.editor; + toolbar.settings = require('./settings'); + toolbar.inline = require('./inline'); + toolbar.toolbox = require('./toolbox'); - toolbar.settings = require('./settings'); - toolbar.inline = require('./inline'); - toolbar.toolbox = require('./toolbox'); - - /** + /** * Margin between focused node and toolbar */ - toolbar.defaultToolbarHeight = 49; + toolbar.defaultToolbarHeight = 49; - toolbar.defaultOffset = 34; + toolbar.defaultOffset = 34; - toolbar.opened = false; + toolbar.opened = false; + toolbar.current = null; + + /** + * @protected + */ + toolbar.open = function () { + if (editor.hideToolbar) { + return; + } + + let toolType = editor.content.currentNode.dataset.tool; + + if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings ) { + editor.nodes.showSettingsButton.classList.add('hide'); + } else { + editor.nodes.showSettingsButton.classList.remove('hide'); + } + + editor.nodes.toolbar.classList.add('opened'); + this.opened = true; + }; + + /** + * @protected + */ + toolbar.close = function () { + editor.nodes.toolbar.classList.remove('opened'); + + toolbar.opened = false; toolbar.current = null; - /** - * @protected - */ - toolbar.open = function () { + for (var button in editor.nodes.toolbarButtons) { + editor.nodes.toolbarButtons[button].classList.remove('selected'); + } - if (editor.hideToolbar) { + /** Close toolbox when toolbar is not displayed */ + editor.toolbar.toolbox.close(); + editor.toolbar.settings.close(); + }; - return; + toolbar.toggle = function () { + if ( !this.opened ) { + this.open(); + } else { + this.close(); + } + }; - } + toolbar.hidePlusButton = function () { + editor.nodes.plusButton.classList.add('hide'); + }; - let toolType = editor.content.currentNode.dataset.tool; + toolbar.showPlusButton = function () { + editor.nodes.plusButton.classList.remove('hide'); + }; - if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings ) { - - editor.nodes.showSettingsButton.classList.add('hide'); - - } else { - - editor.nodes.showSettingsButton.classList.remove('hide'); - - } - - editor.nodes.toolbar.classList.add('opened'); - this.opened = true; - - }; - - /** - * @protected - */ - toolbar.close = function () { - - editor.nodes.toolbar.classList.remove('opened'); - - toolbar.opened = false; - toolbar.current = null; - - for (var button in editor.nodes.toolbarButtons) { - - editor.nodes.toolbarButtons[button].classList.remove('selected'); - - } - - /** Close toolbox when toolbar is not displayed */ - editor.toolbar.toolbox.close(); - editor.toolbar.settings.close(); - - }; - - toolbar.toggle = function () { - - if ( !this.opened ) { - - this.open(); - - } else { - - this.close(); - - } - - }; - - toolbar.hidePlusButton = function () { - - editor.nodes.plusButton.classList.add('hide'); - - }; - - toolbar.showPlusButton = function () { - - editor.nodes.plusButton.classList.remove('hide'); - - }; - - /** + /** * Moving toolbar to the specified node */ - toolbar.move = function () { + toolbar.move = function () { + /** Close Toolbox when we move toolbar */ + editor.toolbar.toolbox.close(); - /** Close Toolbox when we move toolbar */ - editor.toolbar.toolbox.close(); + if (!editor.content.currentNode) { + return; + } - if (!editor.content.currentNode) { + var newYCoordinate = editor.content.currentNode.offsetTop - (editor.toolbar.defaultToolbarHeight / 2) + editor.toolbar.defaultOffset; - return; + editor.nodes.toolbar.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`; - } - - var newYCoordinate = editor.content.currentNode.offsetTop - (editor.toolbar.defaultToolbarHeight / 2) + editor.toolbar.defaultOffset; - - editor.nodes.toolbar.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`; - - /** Close trash actions */ - editor.toolbar.settings.hideRemoveActions(); - - }; - - return toolbar; + /** Close trash actions */ + editor.toolbar.settings.hideRemoveActions(); + }; + return toolbar; })({}); diff --git a/src/components/modules/toolbar/toolbox.js b/src/components/modules/toolbar/toolbox.js index cec3e980..16f4f6d3 100644 --- a/src/components/modules/toolbar/toolbox.js +++ b/src/components/modules/toolbar/toolbox.js @@ -8,184 +8,152 @@ */ module.exports = (function (toolbox) { + let editor = codex.editor; - let editor = codex.editor; + toolbox.opened = false; + toolbox.openedOnBlock = null; - toolbox.opened = false; + /** Shows toolbox */ + toolbox.open = function () { + /** Close setting if toolbox is opened */ + if (editor.toolbar.settings.opened) { + editor.toolbar.settings.close(); + } + + /** Add 'toolbar-opened' class for current block **/ + toolbox.openedOnBlock = editor.content.currentNode; + toolbox.openedOnBlock.classList.add('toolbar-opened'); + + /** display toolbox */ + editor.nodes.toolbox.classList.add('opened'); + + /** Animate plus button */ + editor.nodes.plusButton.classList.add('clicked'); + + /** toolbox state */ + editor.toolbar.toolbox.opened = true; + }; + + /** Closes toolbox */ + toolbox.close = function () { + /** Remove 'toolbar-opened' class from current block **/ + if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened'); toolbox.openedOnBlock = null; - /** Shows toolbox */ - toolbox.open = function () { + /** Makes toolbox disappear */ + editor.nodes.toolbox.classList.remove('opened'); - /** Close setting if toolbox is opened */ - if (editor.toolbar.settings.opened) { + /** Rotate plus button */ + editor.nodes.plusButton.classList.remove('clicked'); - editor.toolbar.settings.close(); + /** toolbox state */ + editor.toolbar.toolbox.opened = false; + editor.toolbar.current = null; + }; + + toolbox.leaf = function () { + let currentTool = editor.toolbar.current, + tools = Object.keys(editor.tools), + barButtons = editor.nodes.toolbarButtons, + nextToolIndex = 0, + toolToSelect, + visibleTool, + tool; + + if ( !currentTool ) { + /** Get first tool from object*/ + for(tool in editor.tools) { + if (editor.tools[tool].displayInToolbox) { + break; } - /** Add 'toolbar-opened' class for current block **/ - toolbox.openedOnBlock = editor.content.currentNode; - toolbox.openedOnBlock.classList.add('toolbar-opened'); + nextToolIndex ++; + } + } else { + nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length; + visibleTool = tools[nextToolIndex]; - /** display toolbox */ - editor.nodes.toolbox.classList.add('opened'); + while (!editor.tools[visibleTool].displayInToolbox) { + nextToolIndex = (nextToolIndex + 1) % tools.length; + visibleTool = tools[nextToolIndex]; + } + } - /** Animate plus button */ - editor.nodes.plusButton.classList.add('clicked'); + toolToSelect = tools[nextToolIndex]; - /** toolbox state */ - editor.toolbar.toolbox.opened = true; + for ( var button in barButtons ) { + barButtons[button].classList.remove('selected'); + } - }; + barButtons[toolToSelect].classList.add('selected'); + editor.toolbar.current = toolToSelect; + }; - /** Closes toolbox */ - toolbox.close = function () { - - /** Remove 'toolbar-opened' class from current block **/ - if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened'); - toolbox.openedOnBlock = null; - - /** Makes toolbox disappear */ - editor.nodes.toolbox.classList.remove('opened'); - - /** Rotate plus button */ - editor.nodes.plusButton.classList.remove('clicked'); - - /** toolbox state */ - editor.toolbar.toolbox.opened = false; - - editor.toolbar.current = null; - - }; - - toolbox.leaf = function () { - - let currentTool = editor.toolbar.current, - tools = Object.keys(editor.tools), - barButtons = editor.nodes.toolbarButtons, - nextToolIndex = 0, - toolToSelect, - visibleTool, - tool; - - if ( !currentTool ) { - - /** Get first tool from object*/ - for(tool in editor.tools) { - - if (editor.tools[tool].displayInToolbox) { - - break; - - } - - nextToolIndex ++; - - } - - } else { - - nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length; - visibleTool = tools[nextToolIndex]; - - while (!editor.tools[visibleTool].displayInToolbox) { - - nextToolIndex = (nextToolIndex + 1) % tools.length; - visibleTool = tools[nextToolIndex]; - - } - - } - - toolToSelect = tools[nextToolIndex]; - - for ( var button in barButtons ) { - - barButtons[button].classList.remove('selected'); - - } - - barButtons[toolToSelect].classList.add('selected'); - editor.toolbar.current = toolToSelect; - - }; - - /** + /** * Transforming selected node type into selected toolbar element type * @param {event} event */ - toolbox.toolClicked = function (event) { - - /** + toolbox.toolClicked = function (event) { + /** * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty */ - var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'], - tool = editor.tools[editor.toolbar.current], - workingNode = editor.content.currentNode, - currentInputIndex = editor.caret.inputIndex, - newBlockContent, - appendCallback, - blockData; + var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'], + tool = editor.tools[editor.toolbar.current], + workingNode = editor.content.currentNode, + currentInputIndex = editor.caret.inputIndex, + newBlockContent, + appendCallback, + blockData; - /** Make block from plugin */ - newBlockContent = tool.render(); - - /** information about block */ - blockData = { - block : newBlockContent, - type : tool.type, - stretched : false - }; - - if ( - workingNode && - UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 && - workingNode.textContent.trim() === '' - ) { - - /** Replace current block */ - editor.content.switchBlock(workingNode, newBlockContent, tool.type); - - } else { - - /** Insert new Block from plugin */ - editor.content.insertBlock(blockData); - - /** increase input index */ - currentInputIndex++; - - } - - /** Fire tool append callback */ - appendCallback = tool.appendCallback; - - if (appendCallback && typeof appendCallback == 'function') { - - appendCallback.call(event); - - } - - window.setTimeout(function () { - - /** Set caret to current block */ - editor.caret.setToBlock(currentInputIndex); - - }, 10); - - - /** - * Changing current Node - */ - editor.content.workingNodeChanged(); - - /** - * Move toolbar when node is changed - */ - editor.toolbar.move(); + /** Make block from plugin */ + newBlockContent = tool.render(); + /** information about block */ + blockData = { + block : newBlockContent, + type : tool.type, + stretched : false }; - return toolbox; + if ( + workingNode && + UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 && + workingNode.textContent.trim() === '' + ) { + /** Replace current block */ + editor.content.switchBlock(workingNode, newBlockContent, tool.type); + } else { + /** Insert new Block from plugin */ + editor.content.insertBlock(blockData); + /** increase input index */ + currentInputIndex++; + } + + /** Fire tool append callback */ + appendCallback = tool.appendCallback; + + if (appendCallback && typeof appendCallback == 'function') { + appendCallback.call(event); + } + + window.setTimeout(function () { + /** Set caret to current block */ + editor.caret.setToBlock(currentInputIndex); + }, 10); + + + /** + * Changing current Node + */ + editor.content.workingNodeChanged(); + + /** + * Move toolbar when node is changed + */ + editor.toolbar.move(); + }; + + return toolbox; })({}); \ No newline at end of file