editor.js/codex-editor.js.map
George Berezhnoy 7f737774bb Fix (#165)
2017-02-23 13:32:41 +03:00

1 line
422 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"version":3,"sources":["webpack:///codex-editor.js","webpack:///webpack/bootstrap 5aa79d46a4d94eef2e64","webpack:///./codex.js","webpack:///./modules/core.js","webpack:///./modules/tools.js","webpack:///./modules/ui.js","webpack:///./modules/transport.js","webpack:///./modules/renderer.js","webpack:///./modules/saver.js","webpack:///./modules/content.js","webpack:///./modules/toolbar/toolbar.js","webpack:///./modules/toolbar/settings.js","webpack:///./modules/toolbar/inline.js","webpack:///./modules/toolbar/toolbox.js","webpack:///./modules/callbacks.js","webpack:///./modules/draw.js","webpack:///./modules/caret.js","webpack:///./modules/notifications.js","webpack:///./modules/parser.js","webpack:///./modules/sanitizer.js","webpack:///./~/html-janitor/src/html-janitor.js","webpack:///./modules/anchors.js","webpack:///./modules/listeners.js","webpack:///./modules/destroyer.js","webpack:///./modules/paste.js"],"names":["codex","modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","editor","version","scriptPrefix","init","core","tools","ui","transport","renderer","saver","content","toolbar","callback","draw","caret","notifications","parser","sanitizer","anchors","listeners","destroyer","paste","settings","textareaId","uploadImagesUrl","initialBlockPlugin","nodes","textarea","wrapper","inlineToolbar","buttons","actions","toolbox","plusButton","showSettingsButton","showTrashButton","blockSettings","pluginSettings","defaultSettings","toolbarButtons","redactor","state","jsonOutput","blocks","inputs","start","userSettings","prepare","then","make","addTools","bindEvents","makeBlocksFromData","saveInputs","catch","error","log","_typeof","Symbol","iterator","obj","constructor","prototype","Promise","resolve","reject","data","hideToolbar","document","getElementById","undefined","Error","msg","type","arg","window","console","e","insertAfter","target","element","parentNode","insertBefore","nextSibling","nodeTypes","TAG","TEXT","COMMENT","keys","BACKSPACE","TAB","ENTER","SHIFT","CTRL","ALT","ESC","SPACE","LEFT","UP","DOWN","RIGHT","DELETE","META","isDomNode","el","nodeType","this","isEmpty","Object","length","ajax","url","XMLHTTP","XMLHttpRequest","ActiveXObject","successFunction","params","async","success","test","encodeURIComponent","withCredentials","beforeSend","open","setRequestHeader","onreadystatechange","readyState","status","responseText","send","importScript","scriptPath","instanceName","script","createElement","defer","onload","onerror","src","head","appendChild","resolve_","reject_","pluginsRequiresPreparation","allPlugins","pluginName","plugin","push","waitAllPluginsPreparation_","plugins","allPluginsProcessed__","reduce","previousValue","iteration","pluginIsReady__","callPluginsPrepareMethod_","available","loadingMessage","config","className","BLOCK_CLASSNAME","BLOCK_CONTENT","BLOCK_STRETCHED","BLOCK_HIGHLIGHTED","BLOCK_IN_FEED_MODE","BLOCK_WITH_ANCHOR","SETTINGS_ITEM","toolbarContent","blockButtons","createHolder","settingsButton","makeRemoveBlockButton","pluginsSettings","makeInlineToolbar","addDefaultSettings","container","inlineToolbarButtons","inlineToolbarActions","tool","toolName","toolButton","iconClassname","render","displayInToolbox","toolbarButton","addInlineToolbarTools","bold","icon","command","italic","underline","link","name","toolbarButtonInline","setInlineToolbarButtonBehaviour","add","globalKeydown","redactorKeyDown","globalKeyup","redactorClicked","plusButtonClicked","showSettingsButtonClicked","button","toolbarButtonClicked","addBlockHandlers","block","blockKeydown","blockPasteCallback","inline","show","querySelectorAll","addInitialBlock","initialBlock","initialBlockType","setAttribute","insertBlock","workingNodeChanged","event","toolClicked","input","arguments","fileSelected","clearInput","files","formdData","FormData","append","selectAndUpload","args","click","xhr","items","appendBlocks","nodeSequence","index","appendNodeAtIndex","getNodeAsync","createBlockFromData","blockData","blocksList","position","toolData","anchor","cover","unavailableBlock","innerHTML","dataset","inputPosition","stretched","isStretched","saveBlocks","html","childNodes","makeQueue","queue","getBlockData","makeFormDataFromBlocks","save","savedData","output","blockContent","pluginsContent","coverFlag","classList","contains","validate","result","currentNode","editorAreaHightlighted","sync","getNodeFocused","focused","selection","getSelection","anchorNode","focusNode","parentElement","isFirstLevelBlock","parent","markBlock","clearMark","remove","getFirstLevelBlock","node","body","targetNode","replaceBlock","targetBlock","newBlock","replaceChild","needPlaceCaret","workingBlock","newBlockContent","blockType","composeNewBlock","currentInputIndex","getCurrentInputIndex","editableElement","querySelector","emptyText","createTextNode","set","move","showPlusButton","setTimeout","setToNextBlock","switchBlock","blockToReplace","newBlockComposed","getDeepestTextNodeFromPosition","text","blockChilds","textContent","trim","removeChild","lookingFromStart","getRange","getRangeAt","splitBlock","inputIndex","textBeforeCaret","textNodeBeforeCaret","textAfterCaret","textNodeAfterCaret","anchorNodeText","caretOffset","anchorOffset","currentBlock","substring","previousChilds","nextChilds","reachedCurrent","child","i","previousChildsLength","nextChildsLength","newNode","NEW_BLOCK_TYPE","mergeBlocks","targetInputIndex","targetInput","currentInputContent","mutation","workingNode","allowedToPaste","sanitize","pasteTextContent","addedNodes","textNode","disconnect","cleaner","satinizer","Config","BASIC","clean","outerHTML","div","replaceWith","isLastNode","allChecked","allSiblingsEmpty_","sibling","wrapTextWithParagraphs","htmlString","paragraph","blockTyped","newWrapper","firstLevelBlocks","indexOf","tagName","cloneNode","getEditableParent","contentEditable","defaultToolbarHeight","defaultOffset","opened","current","close","toggle","hidePlusButton","newYCoordinate","offsetTop","style","transform","Math","floor","hideRemoveActions","setting","toolType","makeSettings","settingsBlock","settingsOpened","feedModeToggler","anchorInput","makeFeedModeToggler","makeAnchorInput","isFeedModeActivated","updateFeedMode","anchorWrapper","hash","placeholder","keyDownOnAnchorInput","keyUpOnAnchorInput","anchorChanged","removeBlockWrapper","settingButton","actionWrapper","confirmAction","cancelAction","removeButtonClicked","confirmRemovingRequest","cancelRemovingRequest","action","showRemoveActions","firstLevelBlocksCount","buttonsOpened","actionsOpened","wrappersOffset","storedSelection","showInlineToolbar","selectedText","getSelectionText","showButtons","getWrappersOffset","newCoordinateX","newCoordinateY","coords","getSelectionCoords","offsetHeight","x","left","y","scrollY","top","closeButtons","closeAction","createLinkAction","defaultToolAction","forEach","hightlight","offset","getOffset","_x","_y","isNaN","offsetLeft","clientLeft","clientTop","offsetParent","range","sel","createRange","collapse","boundingLeft","boundingTop","rangeCount","cloneRange","getClientRects","rect","toString","showActions","inlineToolbarAnchorInputKeydown_","keyCode","editable","restoreSelection","setAnchor","value","preventDefault","stopImmediatePropagation","clearRange","isActive","isLinkActive","saveSelection","inputForLink","focus","dataType","execCommand","containerEl","preSelectionRange","selectNodeContents","setEnd","startContainer","startOffset","end","savedSel","charIndex","setStart","nextCharIndex","nodeStack","foundStart","stop","pop","removeAllRanges","addRange","queryCommandState","setButtonHighlighted","removeButtonsHighLight","tag","leaf","currentTool","barButtons","nextToolIndex","toolToSelect","visibleTool","appendCallback","UNREPLACEBLE_TOOLS","setToBlock","callbacks","enterKeyPressed","tabKeyPressed","enterKeyPressedOnRedactorZone","escapeKeyPressed","defaultKeyPressed","arrowKeyPressed","blockIsEmpty","enterPressedOnBlock","saveCurrentInputIndex","isEnterPressedOnToolbar","enableLineBreaks","stopPropagation","shiftKey","currentSelection","currentSelectedNode","caretAtTheEndOfText","atTheEnd","isTextNodeHasParentBetweenContenteditable","islastNode","detectWhenClickedOnFirstLevelBlockArea","firstLevelBlock","indexOfLastInput","inputIsEmpty","currentNodeType","isInitialType","flag","blockRightOrDownArrowPressed","backspacePressed","blockLeftOrUpArrowPressed","focusedNodeHolder","focusedNode","editableElementIndex","lastChild","deepestTextnode","caretInLastChild","firstChild","caretInFirstChild","caretAtTheBeginning","setToPreviousBlock","selectionLength","endOffset","atStart","_blockPasteCallback","observer","MutationObserver","handleMutationsOnPaste","attributes","childList","characterData","subtree","observe","editableParent","cleanData","fragment","clipboardData","getData","createDocumentFragment","lastNode","allowRenderOnPaste","pasted","deleteContents","insertNode","setStartAfter","mutations","self","currentToolType","ceBlock","bar","toggler","classname","toolIcon","toolTitle","properties","focusedNodeIndex","nodeToSet","childs","nextInput","emptyTextElement","lastChildNode","lengthOfLastChildNode","previousInput","pluginsRender","isFirstNode","isOffsetZero","addToQueue","splice","holder","errorThrown","errorMsg","notification","message","constructorSettings","create","time","okBtn","cancelBtn","okMsg","cancelMsg","confirmHandler","cancelHandler","confirm","cancel","inputField","clear","insertPastedContent","janitor","tags","a","href","rel","b","strong","em","span","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_RESULT__","root","factory","HTMLJanitor","tagDefinitions","validConfigValues","map","k","every","isBlockElement","blockElementNames","nodeName","isInlineElement","inlineElementNames","createTreeWalker","NodeFilter","SHOW_TEXT","SHOW_ELEMENT","SHOW_COMMENT","getAllowedAttrs","shouldRejectNode","allowedAttrs","shouldRejectAttr","attr","attrName","toLowerCase","sandbox","_sanitize","treeWalker","_sanitized","Node","TEXT_NODE","COMMENT_NODE","containsBlockElement","isInline","Array","some","isNotTopContainer","isNestedBlockElement","isInvalid","keepNestedBlockElements","removeAttribute","previousElementSibling","nextElementSibling","newAnchor","rusToTranslit","blur","string","ru","en","split","join","replace","allListeners","search","byElement","context","listenersOnElement","listener","byType","eventType","listenersWithType","byHandler","handler","listenersWithHandler","one","all","isCapture","addEventListener","alreadyAddedListener","removeEventListener","existingListeners","removeAll","get","removeNodes","destroyPlugins","destroy","destroyScripts","scripts","getElementsByTagName","patterns","renderOnPastePatterns","isArray","pattern","clipBoardData","analize","execArray","regex","exec","match","pasteToNewBlock_"],"mappings":"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","file":"codex-editor.js","sourcesContent":["var codex = codex || {}; codex[\"editor\"] =\n/******/ (function(modules) { // webpackBootstrap\n/******/ \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/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\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.loaded = 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// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\r\n\t *\r\n\t * Codex Editor\r\n\t *\r\n\t * @author Codex Team\r\n\t */\n\t\n\tmodule.exports = function (editor) {\n\t\n\t 'use strict';\n\t\n\t editor.version = (\"1.5.2\");\n\t editor.scriptPrefix = 'cdx-script-';\n\t\n\t var init = function init() {\n\t\n\t editor.core = __webpack_require__(1);\n\t editor.tools = __webpack_require__(2);\n\t editor.ui = __webpack_require__(3);\n\t editor.transport = __webpack_require__(4);\n\t editor.renderer = __webpack_require__(5);\n\t editor.saver = __webpack_require__(6);\n\t editor.content = __webpack_require__(7);\n\t editor.toolbar = __webpack_require__(8);\n\t editor.callback = __webpack_require__(12);\n\t editor.draw = __webpack_require__(13);\n\t editor.caret = __webpack_require__(14);\n\t editor.notifications = __webpack_require__(15);\n\t editor.parser = __webpack_require__(16);\n\t editor.sanitizer = __webpack_require__(17);\n\t editor.anchors = __webpack_require__(19);\n\t editor.listeners = __webpack_require__(20);\n\t editor.destroyer = __webpack_require__(21);\n\t editor.paste = __webpack_require__(22);\n\t };\n\t\n\t /**\r\n\t * @public\r\n\t *\r\n\t * holds initial settings\r\n\t */\n\t editor.settings = {\n\t tools: ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n\t textareaId: 'codex-editor',\n\t uploadImagesUrl: '/editor/transport/',\n\t\n\t // Type of block showing on empty editor\n\t initialBlockPlugin: 'paragraph'\n\t };\n\t\n\t /**\r\n\t * public\r\n\t *\r\n\t * Static nodes\r\n\t */\n\t editor.nodes = {\n\t textarea: null,\n\t wrapper: null,\n\t toolbar: null,\n\t inlineToolbar: {\n\t wrapper: null,\n\t buttons: null,\n\t actions: null\n\t },\n\t toolbox: null,\n\t notifications: null,\n\t plusButton: null,\n\t showSettingsButton: null,\n\t showTrashButton: null,\n\t blockSettings: null,\n\t pluginSettings: null,\n\t defaultSettings: null,\n\t toolbarButtons: {}, // { type : DomEl, ... }\n\t redactor: null\n\t };\n\t\n\t /**\r\n\t * @public\r\n\t *\r\n\t * Output state\r\n\t */\n\t editor.state = {\n\t jsonOutput: [],\n\t blocks: [],\n\t inputs: []\n\t };\n\t\n\t /**\r\n\t * @public\r\n\t * Editor plugins\r\n\t */\n\t editor.tools = {};\n\t\n\t /**\r\n\t * Initialization\r\n\t * @uses Promise cEditor.core.prepare\r\n\t * @param {} userSettings are :\r\n\t * - tools [],\r\n\t * - textareaId String\r\n\t * ...\r\n\t *\r\n\t * Load user defined tools\r\n\t * Tools must contain this important objects :\r\n\t * @param {String} type - this is a type of plugin. It can be used as plugin name\r\n\t * @param {String} iconClassname - this a icon in toolbar\r\n\t * @param {Object} make - what should plugin do, when it is clicked\r\n\t * @param {Object} appendCallback - callback after clicking\r\n\t * @param {Element} settings - what settings does it have\r\n\t * @param {Object} render - plugin get JSON, and should return HTML\r\n\t * @param {Object} save - plugin gets HTML content, returns JSON\r\n\t * @param {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\r\n\t * @param {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\r\n\t *\r\n\t * @example\r\n\t * - type : 'header',\r\n\t * - iconClassname : 'ce-icon-header',\r\n\t * - make : headerTool.make,\r\n\t * - appendCallback : headerTool.appendCallback,\r\n\t * - settings : headerTool.makeSettings(),\r\n\t * - render : headerTool.render,\r\n\t * - save : headerTool.save,\r\n\t * - displayInToolbox : true,\r\n\t * - enableLineBreaks : false\r\n\t */\n\t editor.start = function (userSettings) {\n\t\n\t init();\n\t\n\t editor.core.prepare(userSettings)\n\t\n\t // If all ok, make UI, bind events and parse initial-content\n\t .then(editor.ui.make).then(editor.ui.addTools).then(editor.ui.bindEvents).then(editor.tools.prepare).then(editor.paste.prepare).then(editor.transport.prepare).then(editor.renderer.makeBlocksFromData).then(editor.ui.saveInputs).catch(function (error) {\n\t\n\t editor.core.log('Initialization failed with error: %o', 'warn', error);\n\t });\n\t };\n\t\n\t return editor;\n\t}({});\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tvar _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; };\n\t\n\t/**\r\n\t * Codex Editor Core\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.1.2\r\n\t */\n\t\n\tmodule.exports = function (core) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\r\n\t * @public\r\n\t *\r\n\t * Editor preparing method\r\n\t * @return Promise\r\n\t */\n\t core.prepare = function (userSettings) {\n\t\n\t return new Promise(function (resolve, reject) {\n\t\n\t if (userSettings) {\n\t\n\t editor.settings.tools = userSettings.tools || editor.settings.tools;\n\t }\n\t\n\t if (userSettings.data) {\n\t\n\t editor.state.blocks = userSettings.data;\n\t }\n\t\n\t if (userSettings.initialBlockPlugin) {\n\t\n\t editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\n\t }\n\t\n\t if (userSettings.uploadImagesUrl) {\n\t\n\t editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;\n\t }\n\t\n\t editor.hideToolbar = userSettings.hideToolbar;\n\t\n\t editor.nodes.textarea = document.getElementById(userSettings.textareaId || editor.settings.textareaId);\n\t\n\t if (_typeof(editor.nodes.textarea) === undefined || editor.nodes.textarea === null) {\n\t\n\t reject(Error(\"Textarea wasn't found by ID: #\" + userSettings.textareaId));\n\t } else {\n\t\n\t resolve();\n\t }\n\t });\n\t };\n\t\n\t /**\r\n\t * Logging method\r\n\t * @param type = ['log', 'info', 'warn']\r\n\t */\n\t core.log = function (msg, type, arg) {\n\t\n\t type = type || 'log';\n\t\n\t if (!arg) {\n\t\n\t arg = msg || 'undefined';\n\t msg = '[codex-editor]: %o';\n\t } else {\n\t\n\t msg = '[codex-editor]: ' + msg;\n\t }\n\t\n\t try {\n\t\n\t if ('console' in window && window.console[type]) {\n\t\n\t if (arg) window.console[type](msg, arg);else window.console[type](msg);\n\t }\n\t } catch (e) {}\n\t };\n\t\n\t /**\r\n\t * @protected\r\n\t *\r\n\t * Helper for insert one element after another\r\n\t */\n\t core.insertAfter = function (target, element) {\n\t\n\t target.parentNode.insertBefore(element, target.nextSibling);\n\t };\n\t\n\t /**\r\n\t * @const\r\n\t *\r\n\t * Readable DOM-node types map\r\n\t */\n\t core.nodeTypes = {\n\t TAG: 1,\n\t TEXT: 3,\n\t COMMENT: 8\n\t };\n\t\n\t /**\r\n\t * @const\r\n\t * Readable keys map\r\n\t */\n\t core.keys = { BACKSPACE: 8, TAB: 9, ENTER: 13, SHIFT: 16, CTRL: 17, ALT: 18, ESC: 27, SPACE: 32, LEFT: 37, UP: 38, DOWN: 40, RIGHT: 39, DELETE: 46, META: 91 };\n\t\n\t /**\r\n\t * @protected\r\n\t *\r\n\t * Check object for DOM node\r\n\t */\n\t core.isDomNode = function (el) {\n\t\n\t return el && (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG;\n\t };\n\t\n\t /**\r\n\t * Checks passed object for emptiness\r\n\t * @require ES5 - Object.keys\r\n\t * @param {object}\r\n\t */\n\t core.isEmpty = function (obj) {\n\t\n\t return Object.keys(obj).length === 0;\n\t };\n\t\n\t /**\r\n\t * Native Ajax\r\n\t */\n\t core.ajax = function (data) {\n\t\n\t if (!data || !data.url) {\n\t\n\t return;\n\t }\n\t\n\t var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\n\t successFunction = function successFunction() {},\n\t params = '',\n\t obj;\n\t\n\t data.async = true;\n\t data.type = data.type || 'GET';\n\t data.data = data.data || '';\n\t data['content-type'] = data['content-type'] || 'application/json; charset=utf-8';\n\t successFunction = data.success || successFunction;\n\t\n\t if (data.type == 'GET' && data.data) {\n\t\n\t data.url = /\\?/.test(data.url) ? data.url + '&' + data.data : data.url + '?' + data.data;\n\t } else {\n\t\n\t for (obj in data.data) {\n\t\n\t params += obj + '=' + encodeURIComponent(data.data[obj]) + '&';\n\t }\n\t }\n\t\n\t if (data.withCredentials) {\n\t\n\t XMLHTTP.withCredentials = true;\n\t }\n\t\n\t if (data.beforeSend && typeof data.beforeSend == 'function') {\n\t\n\t data.beforeSend.call();\n\t }\n\t\n\t XMLHTTP.open(data.type, data.url, data.async);\n\t XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\t XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n\t\n\t XMLHTTP.onreadystatechange = function () {\n\t\n\t if (XMLHTTP.readyState == 4 && XMLHTTP.status == 200) {\n\t\n\t successFunction(XMLHTTP.responseText);\n\t }\n\t };\n\t\n\t XMLHTTP.send(params);\n\t };\n\t\n\t /**\r\n\t * Appends script to head of document\r\n\t * @return Promise\r\n\t */\n\t core.importScript = function (scriptPath, instanceName) {\n\t\n\t return new Promise(function (resolve, reject) {\n\t\n\t var script = void 0;\n\t\n\t /** Script is already loaded */\n\t if (!instanceName) {\n\t\n\t reject('Instance name is missed');\n\t } else if (document.getElementById(editor.scriptPrefix + instanceName)) {\n\t\n\t resolve(scriptPath);\n\t }\n\t\n\t script = document.createElement('SCRIPT');\n\t script.async = true;\n\t script.defer = true;\n\t script.id = editor.scriptPrefix + instanceName;\n\t\n\t script.onload = function () {\n\t\n\t resolve(scriptPath);\n\t };\n\t\n\t script.onerror = function () {\n\t\n\t reject(scriptPath);\n\t };\n\t\n\t script.src = scriptPath;\n\t document.head.appendChild(script);\n\t });\n\t };\n\t\n\t return core;\n\t}({});\n\n/***/ },\n/* 2 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t* Module working with plugins\r\n\t*/\n\tmodule.exports = function () {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\r\n\t * Initialize plugins before using\r\n\t * Ex. Load scripts or call some internal methods\r\n\t * @return Promise\r\n\t */\n\t function prepare() {\n\t\n\t return new Promise(function (resolve_, reject_) {\n\t\n\t Promise.resolve()\n\t\n\t /**\r\n\t * Compose a sequence of plugins that requires preparation\r\n\t */\n\t .then(function () {\n\t\n\t var pluginsRequiresPreparation = [],\n\t allPlugins = editor.tools;\n\t\n\t for (var pluginName in allPlugins) {\n\t\n\t var plugin = allPlugins[pluginName];\n\t\n\t if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {\n\t\n\t continue;\n\t }\n\t\n\t pluginsRequiresPreparation.push(plugin);\n\t }\n\t\n\t /**\r\n\t * If no one passed plugins requires preparation, finish prepare() and go ahead\r\n\t */\n\t if (!pluginsRequiresPreparation.length) {\n\t\n\t resolve_();\n\t }\n\t\n\t return pluginsRequiresPreparation;\n\t })\n\t\n\t /** Wait plugins while they prepares */\n\t .then(waitAllPluginsPreparation_).then(function () {\n\t\n\t editor.core.log('Plugins loaded', 'info');\n\t resolve_();\n\t }).catch(function (error) {\n\t\n\t reject_(error);\n\t });\n\t });\n\t }\n\t\n\t /**\r\n\t * @param {array} plugins - list of tools that requires preparation\r\n\t * @return {Promise} resolved while all plugins will be ready or failed\r\n\t */\n\t function waitAllPluginsPreparation_(plugins) {\n\t\n\t /**\r\n\t * @calls allPluginsProcessed__ when all plugins prepared or failed\r\n\t */\n\t return new Promise(function (allPluginsProcessed__) {\n\t\n\t /**\r\n\t * pluck each element from queue\r\n\t * First, send resolved Promise as previous value\r\n\t * Each plugins \"prepare\" method returns a Promise, that's why\r\n\t * reduce current element will not be able to continue while can't get\r\n\t * a resolved Promise\r\n\t *\r\n\t * If last plugin is \"prepared\" then go to the next stage of initialization\r\n\t */\n\t plugins.reduce(function (previousValue, plugin, iteration) {\n\t\n\t return previousValue.then(function () {\n\t\n\t /**\r\n\t * Wait till plugins prepared\r\n\t * @calls pluginIsReady__ when plugin is ready or failed\r\n\t */\n\t return new Promise(function (pluginIsReady__) {\n\t\n\t callPluginsPrepareMethod_(plugin).then(pluginIsReady__).then(function () {\n\t\n\t plugin.available = true;\n\t }).catch(function (error) {\n\t\n\t editor.core.log('Plugin \\xAB' + plugin.type + '\\xBB was not loaded. Preparation failed because %o', 'warn', error);\n\t plugin.available = false;\n\t plugin.loadingMessage = error;\n\t\n\t /** Go ahead even some plugin has problems */\n\t pluginIsReady__();\n\t }).then(function () {\n\t\n\t /** If last plugin has problems then just ignore and continue */\n\t if (iteration == plugins.length - 1) {\n\t\n\t allPluginsProcessed__();\n\t }\n\t });\n\t });\n\t });\n\t }, Promise.resolve());\n\t });\n\t }\n\t\n\t var callPluginsPrepareMethod_ = function callPluginsPrepareMethod_(plugin) {\n\t\n\t return plugin.prepare(plugin.config || {});\n\t };\n\t\n\t return {\n\t prepare: prepare\n\t };\n\t}();\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor UI module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.1\r\n\t */\n\t\n\tmodule.exports = function (ui) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\r\n\t * Basic editor classnames\r\n\t */\n\t ui.className = {\n\t\n\t /**\r\n\t * @const {string} BLOCK_CLASSNAME - redactor blocks name\r\n\t */\n\t BLOCK_CLASSNAME: 'ce-block',\n\t\n\t /**\r\n\t * @const {String} wrapper for plugins content\r\n\t */\n\t BLOCK_CONTENT: 'ce-block__content',\n\t\n\t /**\r\n\t * @const {String} BLOCK_STRETCHED - makes block stretched\r\n\t */\n\t BLOCK_STRETCHED: 'ce-block--stretched',\n\t\n\t /**\r\n\t * @const {String} BLOCK_HIGHLIGHTED - adds background\r\n\t */\n\t BLOCK_HIGHLIGHTED: 'ce-block--focused',\n\t\n\t /**\r\n\t * @const {String} - highlights covered blocks\r\n\t */\n\t BLOCK_IN_FEED_MODE: 'ce-block--feed-mode',\n\t\n\t /**\r\n\t * @const {String} - Block with anchor\r\n\t */\n\t BLOCK_WITH_ANCHOR: 'ce-block--anchor',\n\t\n\t /**\r\n\t * @const {String} - for all default settings\r\n\t */\n\t SETTINGS_ITEM: 'ce-settings__item'\n\t\n\t };\n\t\n\t /**\r\n\t * @protected\r\n\t *\r\n\t * Making main interface\r\n\t */\n\t ui.make = function () {\n\t\n\t var wrapper, toolbar, toolbarContent, redactor, blockButtons, blockSettings, showSettingsButton, showTrashButton, toolbox, plusButton;\n\t\n\t /** Make editor wrapper */\n\t wrapper = editor.draw.wrapper();\n\t\n\t /** Append editor wrapper after initial textarea */\n\t editor.core.insertAfter(editor.nodes.textarea, wrapper);\n\t\n\t /** Append block with notifications to the document */\n\t editor.notifications.createHolder();\n\t\n\t /** Make toolbar and content-editable redactor */\n\t toolbar = editor.draw.toolbar();\n\t toolbarContent = editor.draw.toolbarContent();\n\t plusButton = editor.draw.plusButton();\n\t showSettingsButton = editor.draw.settingsButton();\n\t showTrashButton = editor.toolbar.settings.makeRemoveBlockButton();\n\t blockSettings = editor.draw.blockSettings();\n\t blockButtons = editor.draw.blockButtons();\n\t toolbox = editor.draw.toolbox();\n\t redactor = editor.draw.redactor();\n\t\n\t /** settings */\n\t var defaultSettings = editor.draw.defaultSettings(),\n\t pluginSettings = editor.draw.pluginsSettings();\n\t\n\t /** Add default and plugins settings */\n\t blockSettings.appendChild(pluginSettings);\n\t blockSettings.appendChild(defaultSettings);\n\t\n\t /** Make blocks buttons\r\n\t * This block contains settings button and remove block button\r\n\t */\n\t blockButtons.appendChild(showSettingsButton);\n\t blockButtons.appendChild(showTrashButton);\n\t blockButtons.appendChild(blockSettings);\n\t\n\t /** Append plus button */\n\t toolbarContent.appendChild(plusButton);\n\t\n\t /** Appending toolbar tools */\n\t toolbarContent.appendChild(toolbox);\n\t\n\t /** Appending first-level block buttons */\n\t toolbar.appendChild(blockButtons);\n\t\n\t /** Append toolbarContent to toolbar */\n\t toolbar.appendChild(toolbarContent);\n\t\n\t wrapper.appendChild(toolbar);\n\t\n\t wrapper.appendChild(redactor);\n\t\n\t /** Save created ui-elements to static nodes state */\n\t editor.nodes.wrapper = wrapper;\n\t editor.nodes.toolbar = toolbar;\n\t editor.nodes.plusButton = plusButton;\n\t editor.nodes.toolbox = toolbox;\n\t editor.nodes.blockSettings = blockSettings;\n\t editor.nodes.pluginSettings = pluginSettings;\n\t editor.nodes.defaultSettings = defaultSettings;\n\t editor.nodes.showSettingsButton = showSettingsButton;\n\t editor.nodes.showTrashButton = showTrashButton;\n\t\n\t editor.nodes.redactor = redactor;\n\t\n\t /** Make container for inline toolbar */\n\t editor.ui.makeInlineToolbar();\n\t\n\t /** fill in default settings */\n\t editor.toolbar.settings.addDefaultSettings();\n\t };\n\t\n\t ui.makeInlineToolbar = function () {\n\t\n\t var container = editor.draw.inlineToolbar();\n\t\n\t /** Append to redactor new inline block */\n\t editor.nodes.inlineToolbar.wrapper = container;\n\t\n\t /** Draw toolbar buttons */\n\t editor.nodes.inlineToolbar.buttons = editor.draw.inlineToolbarButtons();\n\t\n\t /** Buttons action or settings */\n\t editor.nodes.inlineToolbar.actions = editor.draw.inlineToolbarActions();\n\t\n\t /** Append to inline toolbar buttons as part of it */\n\t editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.buttons);\n\t editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.actions);\n\t\n\t editor.nodes.wrapper.appendChild(editor.nodes.inlineToolbar.wrapper);\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t * Append tools passed in editor.tools\r\n\t */\n\t ui.addTools = function () {\n\t\n\t var tool, toolName, toolButton;\n\t\n\t for (toolName in editor.settings.tools) {\n\t\n\t tool = editor.settings.tools[toolName];\n\t\n\t editor.tools[toolName] = tool;\n\t\n\t if (!tool.iconClassname) {\n\t\n\t editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\n\t continue;\n\t }\n\t\n\t if (typeof tool.render != 'function') {\n\t\n\t editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\n\t continue;\n\t }\n\t\n\t if (!tool.displayInToolbox) {\n\t\n\t continue;\n\t } else {\n\t\n\t /** if tools is for toolbox */\n\t toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\n\t\n\t editor.nodes.toolbox.appendChild(toolButton);\n\t\n\t editor.nodes.toolbarButtons[toolName] = toolButton;\n\t }\n\t }\n\t\n\t /**\r\n\t * Add inline toolbar tools\r\n\t */\n\t editor.ui.addInlineToolbarTools();\n\t };\n\t\n\t ui.addInlineToolbarTools = function () {\n\t\n\t var tools = {\n\t\n\t bold: {\n\t icon: 'ce-icon-bold',\n\t command: 'bold'\n\t },\n\t\n\t italic: {\n\t icon: 'ce-icon-italic',\n\t command: 'italic'\n\t },\n\t\n\t underline: {\n\t icon: 'ce-icon-underline',\n\t command: 'underline'\n\t },\n\t\n\t link: {\n\t icon: 'ce-icon-link',\n\t command: 'createLink'\n\t }\n\t };\n\t\n\t var toolButton, tool;\n\t\n\t for (var name in tools) {\n\t\n\t tool = tools[name];\n\t\n\t toolButton = editor.draw.toolbarButtonInline(name, tool.icon);\n\t\n\t editor.nodes.inlineToolbar.buttons.appendChild(toolButton);\n\t /**\r\n\t * Add callbacks to this buttons\r\n\t */\n\t editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);\n\t }\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t * Bind editor UI events\r\n\t */\n\t ui.bindEvents = function () {\n\t\n\t editor.core.log('ui.bindEvents fired', 'info');\n\t\n\t // window.addEventListener('error', function (errorMsg, url, lineNumber) {\n\t // editor.notifications.errorThrown(errorMsg, event);\n\t // }, false );\n\t\n\t /** All keydowns on Document */\n\t editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n\t\n\t /** All keydowns on Redactor zone */\n\t editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n\t\n\t /** All keydowns on Document */\n\t editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false);\n\t\n\t /**\r\n\t * Mouse click to radactor\r\n\t */\n\t editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false);\n\t\n\t /**\r\n\t * Clicks to the Plus button\r\n\t */\n\t editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n\t\n\t /**\r\n\t * Clicks to SETTINGS button in toolbar\r\n\t */\n\t editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false);\n\t\n\t /**\r\n\t * @deprecated ( but now in use for syncronization );\r\n\t * Any redactor changes: keyboard input, mouse cut/paste, drag-n-drop text\r\n\t */\n\t // editor.nodes.redactor.addEventListener('input', editor.callback.redactorInputEvent, false );\n\t\n\t /** Bind click listeners on toolbar buttons */\n\t for (var button in editor.nodes.toolbarButtons) {\n\t\n\t editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n\t }\n\t };\n\t\n\t ui.addBlockHandlers = function (block) {\n\t\n\t if (!block) return;\n\t\n\t /**\r\n\t * Block keydowns\r\n\t */\n\t editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n\t\n\t /**\r\n\t * Pasting content from another source\r\n\t * We have two type of sanitization\r\n\t * First - uses deep-first search algorithm to get sub nodes,\r\n\t * sanitizes whole Block_content and replaces cleared nodes\r\n\t * This method is deprecated\r\n\t * Method is used in editor.callback.blockPaste(event)\r\n\t *\r\n\t * Secont - uses Mutation observer.\r\n\t * Observer \"observe\" DOM changes and send changings to callback.\r\n\t * Callback gets changed node, not whole Block_content.\r\n\t * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\r\n\t *\r\n\t * Method is used in editor.callback.blockPasteViaSanitize(event)\r\n\t *\r\n\t * @uses html-janitor\r\n\t * @example editor.callback.blockPasteViaSanitize(event), the second method.\r\n\t *\r\n\t */\n\t editor.listeners.add(block, 'paste', editor.callback.blockPasteCallback, false);\n\t\n\t editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\n\t };\n\t\n\t /** getting all contenteditable elements */\n\t ui.saveInputs = function () {\n\t\n\t var redactor = editor.nodes.redactor;\n\t\n\t /** Save all inputs in global variable state */\n\t editor.state.inputs = redactor.querySelectorAll('[contenteditable], input');\n\t };\n\t\n\t /**\r\n\t * Adds first initial block on empty redactor\r\n\t */\n\t ui.addInitialBlock = function () {\n\t\n\t var initialBlockType = editor.settings.initialBlockPlugin,\n\t initialBlock;\n\t\n\t if (!editor.tools[initialBlockType]) {\n\t\n\t editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\n\t return;\n\t }\n\t\n\t initialBlock = editor.tools[initialBlockType].render();\n\t\n\t initialBlock.setAttribute('data-placeholder', 'Расскажите свою историю...');\n\t\n\t editor.content.insertBlock({\n\t type: initialBlockType,\n\t block: initialBlock\n\t });\n\t\n\t editor.content.workingNodeChanged(initialBlock);\n\t };\n\t\n\t ui.setInlineToolbarButtonBehaviour = function (button, type) {\n\t\n\t editor.listeners.add(button, 'mousedown', function (event) {\n\t\n\t editor.toolbar.inline.toolClicked(event, type);\n\t }, false);\n\t };\n\t\n\t return ui;\n\t}({});\n\n/***/ },\n/* 4 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t *\r\n\t * Codex.Editor Transport Module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (transport) {\n\t\n\t var editor = codex.editor;\n\t\n\t transport.input = null;\n\t\n\t /**\r\n\t * @property {Object} arguments - keep plugin settings and defined callbacks\r\n\t */\n\t transport.arguments = null;\n\t\n\t transport.prepare = function () {\n\t\n\t var input = document.createElement('INPUT');\n\t\n\t input.type = 'file';\n\t editor.listeners.add(input, 'change', editor.transport.fileSelected);\n\t\n\t editor.transport.input = input;\n\t };\n\t\n\t /** Clear input when files is uploaded */\n\t transport.clearInput = function () {\n\t\n\t /** Remove old input */\n\t this.input = null;\n\t\n\t /** Prepare new one */\n\t this.prepare();\n\t };\n\t\n\t /**\r\n\t * Callback for file selection\r\n\t * @param {Event} event\r\n\t */\n\t transport.fileSelected = function () {\n\t\n\t var input = this,\n\t files = input.files,\n\t formdData = new FormData();\n\t\n\t formdData.append('files', files[0], files[0].name);\n\t\n\t editor.transport.ajax({\n\t data: formdData,\n\t beforeSend: editor.transport.arguments.beforeSend,\n\t success: editor.transport.arguments.success,\n\t error: editor.transport.arguments.error\n\t });\n\t };\n\t\n\t /**\r\n\t * Use plugin callbacks\r\n\t * @protected\r\n\t */\n\t transport.selectAndUpload = function (args) {\n\t\n\t this.arguments = args;\n\t this.input.click();\n\t };\n\t\n\t /**\r\n\t * Ajax requests module\r\n\t * @todo use core.ajax\r\n\t */\n\t transport.ajax = function (params) {\n\t\n\t var xhr = new XMLHttpRequest(),\n\t beforeSend = typeof params.beforeSend == 'function' ? params.beforeSend : function () {},\n\t success = typeof params.success == 'function' ? params.success : function () {},\n\t error = typeof params.error == 'function' ? params.error : function () {};\n\t\n\t beforeSend();\n\t\n\t xhr.open('POST', editor.settings.uploadImagesUrl, true);\n\t\n\t xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\t\n\t xhr.onload = function () {\n\t\n\t if (xhr.status === 200) {\n\t\n\t success(xhr.responseText);\n\t } else {\n\t\n\t editor.core.log('request error: %o', xhr);\n\t error();\n\t }\n\t };\n\t\n\t xhr.send(params.data);\n\t this.clearInput();\n\t };\n\t\n\t return transport;\n\t}({});\n\n/***/ },\n/* 5 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Renderer Module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (renderer) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\r\n\t * Asyncronously parses input JSON to redactor blocks\r\n\t */\n\t renderer.makeBlocksFromData = function () {\n\t\n\t /**\r\n\t * If redactor is empty, add first paragraph to start writing\r\n\t */\n\t if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {\n\t\n\t editor.ui.addInitialBlock();\n\t return;\n\t }\n\t\n\t Promise.resolve()\n\t\n\t /** First, get JSON from state */\n\t .then(function () {\n\t\n\t return editor.state.blocks;\n\t })\n\t\n\t /** Then, start to iterate they */\n\t .then(editor.renderer.appendBlocks)\n\t\n\t /** Write log if something goes wrong */\n\t .catch(function (error) {\n\t\n\t editor.core.log('Error while parsing JSON: %o', 'error', error);\n\t });\n\t };\n\t\n\t /**\r\n\t * Parses JSON to blocks\r\n\t * @param {object} data\r\n\t * @return Primise -> nodeList\r\n\t */\n\t renderer.appendBlocks = function (data) {\n\t\n\t var blocks = data.items;\n\t\n\t /**\r\n\t * Sequence of one-by-one blocks appending\r\n\t * Uses to save blocks order after async-handler\r\n\t */\n\t var nodeSequence = Promise.resolve();\n\t\n\t for (var index = 0; index < blocks.length; index++) {\n\t\n\t /** Add node to sequence at specified index */\n\t editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\n\t }\n\t };\n\t\n\t /**\r\n\t * Append node at specified index\r\n\t */\n\t renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\n\t\n\t /** We need to append node to sequence */\n\t nodeSequence\n\t\n\t /** first, get node async-aware */\n\t .then(function () {\n\t\n\t return editor.renderer.getNodeAsync(blocks, index);\n\t })\n\t\n\t /**\r\n\t * second, compose editor-block from JSON object\r\n\t */\n\t .then(editor.renderer.createBlockFromData)\n\t\n\t /**\r\n\t * now insert block to redactor\r\n\t */\n\t .then(function (blockData) {\n\t\n\t /**\r\n\t * blockData has 'block', 'type' and 'stretched' information\r\n\t */\n\t editor.content.insertBlock(blockData);\n\t\n\t /** Pass created block to next step */\n\t return blockData.block;\n\t })\n\t\n\t /** Log if something wrong with node */\n\t .catch(function (error) {\n\t\n\t editor.core.log('Node skipped while parsing because %o', 'error', error);\n\t });\n\t };\n\t\n\t /**\r\n\t * Asynchronously returns block data from blocksList by index\r\n\t * @return Promise to node\r\n\t */\n\t renderer.getNodeAsync = function (blocksList, index) {\n\t\n\t return Promise.resolve().then(function () {\n\t\n\t return {\n\t tool: blocksList[index],\n\t position: index\n\t };\n\t });\n\t };\n\t\n\t /**\r\n\t * Creates editor block by JSON-data\r\n\t *\r\n\t * @uses render method of each plugin\r\n\t *\r\n\t * @param {Object} toolData.tool\r\n\t * { header : {\r\n\t * text: '',\r\n\t * type: 'H3', ...\r\n\t * }\r\n\t * }\r\n\t * @param {Number} toolData.position - index in input-blocks array\r\n\t * @return {Object} with type and Element\r\n\t */\n\t renderer.createBlockFromData = function (toolData) {\n\t\n\t /** New parser */\n\t var block,\n\t tool = toolData.tool,\n\t pluginName = tool.type,\n\t anchor = tool.anchor,\n\t cover = tool.cover;\n\t\n\t /** Get first key of object that stores plugin name */\n\t // for (var pluginName in blockData) break;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].render != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have \\xABrender\\xBB method');\n\t }\n\t\n\t if (editor.tools[pluginName].available === false) {\n\t\n\t block = editor.draw.unavailableBlock();\n\t\n\t block.innerHTML = editor.tools[pluginName].loadingMessage;\n\t\n\t /**\r\n\t * Saver will extract data from initial block data by position in array\r\n\t */\n\t block.dataset.inputPosition = toolData.position;\n\t } else {\n\t\n\t /** New Parser */\n\t block = editor.tools[pluginName].render(tool.data);\n\t }\n\t\n\t /** is first-level block stretched */\n\t var stretched = editor.tools[pluginName].isStretched || false;\n\t\n\t /** Retrun type and block */\n\t return {\n\t type: pluginName,\n\t block: block,\n\t stretched: stretched,\n\t cover: cover,\n\t anchor: anchor\n\t };\n\t };\n\t\n\t return renderer;\n\t}({});\n\n/***/ },\n/* 6 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Saver\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0.2\r\n\t */\n\t\n\tmodule.exports = function (saver) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\r\n\t * Saves blocks\r\n\t * @private\r\n\t */\n\t saver.saveBlocks = function () {\n\t\n\t /** Save html content of redactor to memory */\n\t editor.state.html = editor.nodes.redactor.innerHTML;\n\t\n\t /** Empty jsonOutput state */\n\t editor.state.jsonOutput = [];\n\t\n\t Promise.resolve().then(function () {\n\t\n\t return editor.nodes.redactor.childNodes;\n\t })\n\t /** Making a sequence from separate blocks */\n\t .then(editor.saver.makeQueue).then(function () {\n\t // editor.nodes.textarea.innerHTML = editor.state.html;\n\t }).catch(function (error) {\n\t\n\t editor.core.log(error);\n\t });\n\t };\n\t\n\t saver.makeQueue = function (blocks) {\n\t\n\t var queue = Promise.resolve();\n\t\n\t for (var index = 0; index < blocks.length; index++) {\n\t\n\t /** Add node to sequence at specified index */\n\t editor.saver.getBlockData(queue, blocks, index);\n\t }\n\t };\n\t\n\t /** Gets every block and makes From Data */\n\t saver.getBlockData = function (queue, blocks, index) {\n\t\n\t queue.then(function () {\n\t\n\t return editor.saver.getNodeAsync(blocks, index);\n\t }).then(editor.saver.makeFormDataFromBlocks);\n\t };\n\t\n\t /**\r\n\t * Asynchronously returns block data from blocksList by index\r\n\t * @return Promise to node\r\n\t */\n\t saver.getNodeAsync = function (blocksList, index) {\n\t\n\t return Promise.resolve().then(function () {\n\t\n\t return blocksList[index];\n\t });\n\t };\n\t\n\t saver.makeFormDataFromBlocks = function (block) {\n\t\n\t var pluginName = block.dataset.tool,\n\t anchor = block.dataset.anchor;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].save != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have save method');\n\t }\n\t\n\t /** Result saver */\n\t var blockContent = block.childNodes[0],\n\t pluginsContent = blockContent.childNodes[0],\n\t savedData,\n\t position,\n\t output,\n\t coverFlag = false;\n\t\n\t /** If plugin wasn't available then return data from cache */\n\t if (editor.tools[pluginName].available === false) {\n\t\n\t position = pluginsContent.dataset.inputPosition;\n\t\n\t savedData = codex.editor.state.blocks.items[position].data;\n\t coverFlag = codex.editor.state.blocks.items[position].cover;\n\t anchor = codex.editor.state.blocks.items[position].anchor;\n\t } else {\n\t\n\t savedData = editor.tools[pluginName].save(pluginsContent);\n\t coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t\n\t if (editor.tools[pluginName].validate) {\n\t\n\t var result = editor.tools[pluginName].validate(savedData);\n\t\n\t /**\r\n\t * Do not allow invalid data\r\n\t */\n\t if (!result) return;\n\t }\n\t }\n\t\n\t output = {\n\t type: pluginName,\n\t anchor: anchor,\n\t data: savedData\n\t };\n\t\n\t /** Marks Blocks that will be in main page */\n\t output.cover = coverFlag;\n\t\n\t editor.state.jsonOutput.push(output);\n\t };\n\t\n\t return saver;\n\t}({});\n\n/***/ },\n/* 7 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Content Module\r\n\t * Works with DOM\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.3.11\r\n\t */\n\t\n\tmodule.exports = function (content) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\r\n\t * Links to current active block\r\n\t * @type {null | Element}\r\n\t */\n\t content.currentNode = null;\n\t\n\t /**\r\n\t * clicked in redactor area\r\n\t * @type {null | Boolean}\r\n\t */\n\t content.editorAreaHightlighted = null;\n\t\n\t /**\r\n\t * Synchronizes redactor with original textarea\r\n\t */\n\t content.sync = function () {\n\t\n\t editor.core.log('syncing...');\n\t\n\t /**\r\n\t * Save redactor content to editor.state\r\n\t */\n\t editor.state.html = editor.nodes.redactor.innerHTML;\n\t };\n\t\n\t /**\r\n\t * @deprecated\r\n\t */\n\t content.getNodeFocused = function () {\n\t\n\t var selection = window.getSelection(),\n\t focused;\n\t\n\t if (selection.anchorNode === null) {\n\t\n\t return null;\n\t }\n\t\n\t if (selection.anchorNode.nodeType == editor.core.nodeTypes.TAG) {\n\t\n\t focused = selection.anchorNode;\n\t } else {\n\t\n\t focused = selection.focusNode.parentElement;\n\t }\n\t\n\t if (!editor.parser.isFirstLevelBlock(focused)) {\n\t\n\t /** Iterate with parent nodes to find first-level*/\n\t var parent = focused.parentNode;\n\t\n\t while (parent && !editor.parser.isFirstLevelBlock(parent)) {\n\t\n\t parent = parent.parentNode;\n\t }\n\t\n\t focused = parent;\n\t }\n\t\n\t if (focused != editor.nodes.redactor) {\n\t\n\t return focused;\n\t }\n\t\n\t return null;\n\t };\n\t\n\t /**\r\n\t * Appends background to the block\r\n\t */\n\t content.markBlock = function () {\n\t\n\t editor.content.currentNode.classList.add(editor.ui.className.BLOCK_HIGHLIGHTED);\n\t };\n\t\n\t /**\r\n\t * Clear background\r\n\t */\n\t content.clearMark = function () {\n\t\n\t if (editor.content.currentNode) {\n\t\n\t editor.content.currentNode.classList.remove(editor.ui.className.BLOCK_HIGHLIGHTED);\n\t }\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Finds first-level block\r\n\t * @param {Element} node - selected or clicked in redactors area node\r\n\t */\n\t content.getFirstLevelBlock = function (node) {\n\t\n\t if (!editor.core.isDomNode(node)) {\n\t\n\t node = node.parentNode;\n\t }\n\t\n\t if (node === editor.nodes.redactor || node === document.body) {\n\t\n\t return null;\n\t } else {\n\t\n\t while (!node.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\n\t\n\t node = node.parentNode;\n\t }\n\t\n\t return node;\n\t }\n\t };\n\t\n\t /**\r\n\t * Trigger this event when working node changed\r\n\t * @param {Element} targetNode - first-level of this node will be current\r\n\t * If targetNode is first-level then we set it as current else we look for parents to find first-level\r\n\t */\n\t content.workingNodeChanged = function (targetNode) {\n\t\n\t /** Clear background from previous marked block before we change */\n\t editor.content.clearMark();\n\t\n\t if (!targetNode) {\n\t\n\t return;\n\t }\n\t\n\t this.currentNode = this.getFirstLevelBlock(targetNode);\n\t };\n\t\n\t /**\r\n\t * Replaces one redactor block with another\r\n\t * @protected\r\n\t * @param {Element} targetBlock - block to replace. Mostly currentNode.\r\n\t * @param {Element} newBlock\r\n\t * @param {string} newBlockType - type of new block; we need to store it to data-attribute\r\n\t *\r\n\t * [!] Function does not saves old block content.\r\n\t * You can get it manually and pass with newBlock.innerHTML\r\n\t */\n\t content.replaceBlock = function (targetBlock, newBlock) {\n\t\n\t if (!targetBlock || !newBlock) {\n\t\n\t editor.core.log('replaceBlock: missed params');\n\t return;\n\t }\n\t\n\t /** If target-block is not a frist-level block, then we iterate parents to find it */\n\t while (!targetBlock.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\n\t\n\t targetBlock = targetBlock.parentNode;\n\t }\n\t\n\t /**\r\n\t * Check is this block was in feed\r\n\t * If true, than set switched block also covered\r\n\t */\n\t if (targetBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE)) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t }\n\t\n\t if (targetBlock.classList.contains(editor.ui.className.BLOCK_WITH_ANCHOR)) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t\n\t /**\r\n\t * Saving anchor\r\n\t */\n\t newBlock.dataset.anchor = targetBlock.dataset.anchor;\n\t\n\t /** Replacing */\n\t editor.nodes.redactor.replaceChild(newBlock, targetBlock);\n\t\n\t /**\r\n\t * Set new node as current\r\n\t */\n\t editor.content.workingNodeChanged(newBlock);\n\t\n\t /**\r\n\t * Add block handlers\r\n\t */\n\t editor.ui.addBlockHandlers(newBlock);\n\t\n\t /**\r\n\t * Save changes\r\n\t */\n\t editor.ui.saveInputs();\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Inserts new block to redactor\r\n\t * Wrapps block into a DIV with BLOCK_CLASSNAME class\r\n\t *\r\n\t * @param blockData {object}\r\n\t * @param blockData.block {Element} element with block content\r\n\t * @param blockData.type {string} block plugin\r\n\t * @param needPlaceCaret {bool} pass true to set caret in new block\r\n\t *\r\n\t */\n\t content.insertBlock = function (blockData, needPlaceCaret) {\n\t\n\t var workingBlock = editor.content.currentNode,\n\t newBlockContent = blockData.block,\n\t blockType = blockData.type,\n\t cover = blockData.cover,\n\t anchor = blockData.anchor,\n\t isStretched = blockData.stretched;\n\t\n\t var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);\n\t\n\t if (cover === true) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t }\n\t\n\t if (anchor) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t\n\t if (workingBlock) {\n\t\n\t editor.core.insertAfter(workingBlock, newBlock);\n\t } else {\n\t\n\t /**\r\n\t * If redactor is empty, append as first child\r\n\t */\n\t editor.nodes.redactor.appendChild(newBlock);\n\t }\n\t\n\t /**\r\n\t * Block handler\r\n\t */\n\t editor.ui.addBlockHandlers(newBlock);\n\t\n\t /**\r\n\t * Set new node as current\r\n\t */\n\t editor.content.workingNodeChanged(newBlock);\n\t\n\t /**\r\n\t * Save changes\r\n\t */\n\t editor.ui.saveInputs();\n\t\n\t if (needPlaceCaret) {\n\t\n\t /**\r\n\t * If we don't know input index then we set default value -1\r\n\t */\n\t var currentInputIndex = editor.caret.getCurrentInputIndex() || -1;\n\t\n\t if (currentInputIndex == -1) {\n\t\n\t var editableElement = newBlock.querySelector('[contenteditable]'),\n\t emptyText = document.createTextNode('');\n\t\n\t editableElement.appendChild(emptyText);\n\t editor.caret.set(editableElement, 0, 0);\n\t\n\t editor.toolbar.move();\n\t editor.toolbar.showPlusButton();\n\t } else {\n\t\n\t if (currentInputIndex === editor.state.inputs.length - 1) return;\n\t\n\t /** Timeout for browsers execution */\n\t window.setTimeout(function () {\n\t\n\t /** Setting to the new input */\n\t editor.caret.setToNextBlock(currentInputIndex);\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t }, 10);\n\t }\n\t }\n\t\n\t /**\r\n\t * Block is inserted, wait for new click that defined focusing on editors area\r\n\t * @type {boolean}\r\n\t */\n\t content.editorAreaHightlighted = false;\n\t };\n\t\n\t /**\r\n\t * Replaces blocks with saving content\r\n\t * @protected\r\n\t * @param {Element} noteToReplace\r\n\t * @param {Element} newNode\r\n\t * @param {Element} blockType\r\n\t */\n\t content.switchBlock = function (blockToReplace, newBlock, tool) {\n\t\n\t var newBlockComposed = editor.content.composeNewBlock(newBlock, tool);\n\t\n\t /** Replacing */\n\t editor.content.replaceBlock(blockToReplace, newBlockComposed);\n\t\n\t /** Save new Inputs when block is changed */\n\t editor.ui.saveInputs();\n\t };\n\t\n\t /**\r\n\t * Iterates between child noted and looking for #text node on deepest level\r\n\t * @private\r\n\t * @param {Element} block - node where find\r\n\t * @param {int} postiton - starting postion\r\n\t * Example: childNodex.length to find from the end\r\n\t * or 0 to find from the start\r\n\t * @return {Text} block\r\n\t * @uses DFS\r\n\t */\n\t content.getDeepestTextNodeFromPosition = function (block, position) {\n\t\n\t /**\r\n\t * Clear Block from empty and useless spaces with trim.\r\n\t * Such nodes we should remove\r\n\t */\n\t var blockChilds = block.childNodes,\n\t index,\n\t node,\n\t text;\n\t\n\t for (index = 0; index < blockChilds.length; index++) {\n\t\n\t node = blockChilds[index];\n\t\n\t if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\t\n\t text = node.textContent.trim();\n\t\n\t /** Text is empty. We should remove this child from node before we start DFS\r\n\t * decrease the quantity of childs.\r\n\t */\n\t if (text === '') {\n\t\n\t block.removeChild(node);\n\t position--;\n\t }\n\t }\n\t }\n\t\n\t if (block.childNodes.length === 0) {\n\t\n\t return document.createTextNode('');\n\t }\n\t\n\t /** Setting default position when we deleted all empty nodes */\n\t if (position < 0) position = 1;\n\t\n\t var lookingFromStart = false;\n\t\n\t /** For looking from START */\n\t if (position === 0) {\n\t\n\t lookingFromStart = true;\n\t position = 1;\n\t }\n\t\n\t while (position) {\n\t\n\t /** initial verticle of node. */\n\t if (lookingFromStart) {\n\t\n\t block = block.childNodes[0];\n\t } else {\n\t\n\t block = block.childNodes[position - 1];\n\t }\n\t\n\t if (block.nodeType == editor.core.nodeTypes.TAG) {\n\t\n\t position = block.childNodes.length;\n\t } else if (block.nodeType == editor.core.nodeTypes.TEXT) {\n\t\n\t position = 0;\n\t }\n\t }\n\t\n\t return block;\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t */\n\t content.composeNewBlock = function (block, tool, isStretched, anchor) {\n\t\n\t var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),\n\t blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});\n\t\n\t blockContent.appendChild(block);\n\t newBlock.appendChild(blockContent);\n\t\n\t if (isStretched) {\n\t\n\t blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED);\n\t }\n\t\n\t newBlock.dataset.tool = tool;\n\t newBlock.dataset.anchor = anchor || '';\n\t return newBlock;\n\t };\n\t\n\t /**\r\n\t * Returns Range object of current selection\r\n\t */\n\t content.getRange = function () {\n\t\n\t var selection = window.getSelection().getRangeAt(0);\n\t\n\t return selection;\n\t };\n\t\n\t /**\r\n\t * Divides block in two blocks (after and before caret)\r\n\t * @private\r\n\t * @param {Int} inputIndex - target input index\r\n\t */\n\t content.splitBlock = function (inputIndex) {\n\t\n\t var selection = window.getSelection(),\n\t anchorNode = selection.anchorNode,\n\t anchorNodeText = anchorNode.textContent,\n\t caretOffset = selection.anchorOffset,\n\t textBeforeCaret,\n\t textNodeBeforeCaret,\n\t textAfterCaret,\n\t textNodeAfterCaret;\n\t\n\t var currentBlock = editor.content.currentNode.querySelector('[contentEditable]');\n\t\n\t textBeforeCaret = anchorNodeText.substring(0, caretOffset);\n\t textAfterCaret = anchorNodeText.substring(caretOffset);\n\t\n\t textNodeBeforeCaret = document.createTextNode(textBeforeCaret);\n\t\n\t if (textAfterCaret) {\n\t\n\t textNodeAfterCaret = document.createTextNode(textAfterCaret);\n\t }\n\t\n\t var previousChilds = [],\n\t nextChilds = [],\n\t reachedCurrent = false;\n\t\n\t if (textNodeAfterCaret) {\n\t\n\t nextChilds.push(textNodeAfterCaret);\n\t }\n\t\n\t for (var i = 0, child; !!(child = currentBlock.childNodes[i]); i++) {\n\t\n\t if (child != anchorNode) {\n\t\n\t if (!reachedCurrent) {\n\t\n\t previousChilds.push(child);\n\t } else {\n\t\n\t nextChilds.push(child);\n\t }\n\t } else {\n\t\n\t reachedCurrent = true;\n\t }\n\t }\n\t\n\t /** Clear current input */\n\t editor.state.inputs[inputIndex].innerHTML = '';\n\t\n\t /**\r\n\t * Append all childs founded before anchorNode\r\n\t */\n\t var previousChildsLength = previousChilds.length;\n\t\n\t for (i = 0; i < previousChildsLength; i++) {\n\t\n\t editor.state.inputs[inputIndex].appendChild(previousChilds[i]);\n\t }\n\t\n\t editor.state.inputs[inputIndex].appendChild(textNodeBeforeCaret);\n\t\n\t /**\r\n\t * Append text node which is after caret\r\n\t */\n\t var nextChildsLength = nextChilds.length,\n\t newNode = document.createElement('div');\n\t\n\t for (i = 0; i < nextChildsLength; i++) {\n\t\n\t newNode.appendChild(nextChilds[i]);\n\t }\n\t\n\t newNode = newNode.innerHTML;\n\t\n\t /** This type of block creates when enter is pressed */\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\t\n\t /**\r\n\t * Make new paragraph with text after caret\r\n\t */\n\t editor.content.insertBlock({\n\t type: NEW_BLOCK_TYPE,\n\t block: editor.tools[NEW_BLOCK_TYPE].render({\n\t text: newNode\n\t })\n\t }, true);\n\t };\n\t\n\t /**\r\n\t * Merges two blocks — current and target\r\n\t * If target index is not exist, then previous will be as target\r\n\t */\n\t content.mergeBlocks = function (currentInputIndex, targetInputIndex) {\n\t\n\t /** If current input index is zero, then prevent method execution */\n\t if (currentInputIndex === 0) {\n\t\n\t return;\n\t }\n\t\n\t var targetInput,\n\t currentInputContent = editor.state.inputs[currentInputIndex].innerHTML;\n\t\n\t if (!targetInputIndex) {\n\t\n\t targetInput = editor.state.inputs[currentInputIndex - 1];\n\t } else {\n\t\n\t targetInput = editor.state.inputs[targetInputIndex];\n\t }\n\t\n\t targetInput.innerHTML += currentInputContent;\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Callback for HTML Mutations\r\n\t * @param {Array} mutation - Mutation Record\r\n\t */\n\t content.paste = function (mutation) {\n\t\n\t var workingNode = editor.content.currentNode,\n\t tool = workingNode.dataset.tool;\n\t\n\t if (editor.tools[tool].allowedToPaste) {\n\t\n\t editor.content.sanitize.call(this, mutation.target);\n\t } else {\n\t\n\t editor.content.pasteTextContent(mutation.addedNodes);\n\t }\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * gets only text/plain content of node\r\n\t * @param {Element} target - HTML node\r\n\t */\n\t content.pasteTextContent = function (nodes) {\n\t\n\t var node = nodes[0],\n\t textNode;\n\t\n\t if (!node) {\n\t\n\t return;\n\t }\n\t\n\t if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\t\n\t textNode = document.createTextNode(node);\n\t } else {\n\t\n\t textNode = document.createTextNode(node.textContent);\n\t }\n\t\n\t if (editor.core.isDomNode(node)) {\n\t\n\t node.parentNode.replaceChild(textNode, node);\n\t }\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Sanitizes HTML content\r\n\t * @param {Element} target - inserted element\r\n\t * @uses Sanitize library html-janitor\r\n\t */\n\t content.sanitize = function (target) {\n\t\n\t if (!target) {\n\t\n\t return;\n\t }\n\t\n\t var node = target[0];\n\t\n\t if (!node) {\n\t\n\t return;\n\t }\n\t\n\t /**\r\n\t * Disconnect Observer\r\n\t * hierarchy of function calls inherits context of observer\r\n\t */\n\t this.disconnect();\n\t\n\t /**\r\n\t * Don't sanitize text node\r\n\t */\n\t if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\t\n\t return;\n\t }\n\t\n\t /**\r\n\t * Clear dirty content\r\n\t */\n\t var cleaner = editor.sanitizer.init(editor.satinizer.Config.BASIC),\n\t clean = cleaner.clean(target.outerHTML);\n\t\n\t var div = editor.draw.node('DIV', [], { innerHTML: clean });\n\t\n\t node.replaceWith(div.childNodes[0]);\n\t };\n\t\n\t /**\r\n\t * Iterates all right siblings and parents, which has right siblings\r\n\t * while it does not reached the first-level block\r\n\t *\r\n\t * @param {Element} node\r\n\t * @return {boolean}\r\n\t */\n\t content.isLastNode = function (node) {\n\t\n\t // console.log('погнали перебор родителей');\n\t\n\t var allChecked = false;\n\t\n\t while (!allChecked) {\n\t\n\t // console.log('Смотрим на %o', node);\n\t // console.log('Проверим, пустые ли соседи справа');\n\t\n\t if (!allSiblingsEmpty_(node)) {\n\t\n\t // console.log('Есть непустые соседи. Узел не последний. Выходим.');\n\t return false;\n\t }\n\t\n\t node = node.parentNode;\n\t\n\t /**\r\n\t * Проверяем родителей до тех пор, пока не найдем блок первого уровня\r\n\t */\n\t if (node.classList.contains(editor.ui.className.BLOCK_CONTENT)) {\n\t\n\t allChecked = true;\n\t }\n\t }\n\t\n\t return true;\n\t };\n\t\n\t /**\r\n\t * Checks if all element right siblings is empty\r\n\t * @param node\r\n\t */\n\t var allSiblingsEmpty_ = function allSiblingsEmpty_(node) {\n\t\n\t /**\r\n\t * Нужно убедиться, что после пустого соседа ничего нет\r\n\t */\n\t var sibling = node.nextSibling;\n\t\n\t while (sibling) {\n\t\n\t if (sibling.textContent.length) {\n\t\n\t return false;\n\t }\n\t\n\t sibling = sibling.nextSibling;\n\t }\n\t\n\t return true;\n\t };\n\t\n\t /**\r\n\t * @public\r\n\t *\r\n\t * @param [String] htmlString - html content as string\r\n\t * @return {string} - html content as string\r\n\t */\n\t content.wrapTextWithParagraphs = function (htmlString) {\n\t\n\t var wrapper = document.createElement('DIV'),\n\t newWrapper = document.createElement('DIV'),\n\t i,\n\t paragraph,\n\t firstLevelBlocks = ['DIV', 'P'],\n\t blockTyped,\n\t node;\n\t\n\t /**\r\n\t * Make HTML Element to Wrap Text\r\n\t * It allows us to work with input data as HTML content\r\n\t */\n\t wrapper.innerHTML = htmlString;\n\t paragraph = document.createElement('P');\n\t\n\t for (i = 0; i < wrapper.childNodes.length; i++) {\n\t\n\t node = wrapper.childNodes[i];\n\t\n\t blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1;\n\t\n\t /**\r\n\t * If node is first-levet\r\n\t * we add this node to our new wrapper\r\n\t */\n\t if (blockTyped) {\n\t\n\t /**\r\n\t * If we had splitted inline nodes to paragraph before\r\n\t */\n\t if (paragraph.childNodes.length) {\n\t\n\t newWrapper.appendChild(paragraph.cloneNode(true));\n\t\n\t /** empty paragraph */\n\t paragraph = null;\n\t paragraph = document.createElement('P');\n\t }\n\t\n\t newWrapper.appendChild(node.cloneNode(true));\n\t } else {\n\t\n\t /** Collect all inline nodes to one as paragraph */\n\t paragraph.appendChild(node.cloneNode(true));\n\t\n\t /** if node is last we should append this node to paragraph and paragraph to new wrapper */\n\t if (i == wrapper.childNodes.length - 1) {\n\t\n\t newWrapper.appendChild(paragraph.cloneNode(true));\n\t }\n\t }\n\t }\n\t\n\t return newWrapper.innerHTML;\n\t };\n\t\n\t /**\r\n\t * Finds closest Contenteditable parent from Element\r\n\t * @param {Element} node element looking from\r\n\t * @return {Element} node contenteditable\r\n\t */\n\t content.getEditableParent = function (node) {\n\t\n\t while (node && node.contentEditable != 'true') {\n\t\n\t node = node.parentNode;\n\t }\n\t\n\t return node;\n\t };\n\t\n\t return content;\n\t}({});\n\n/***/ },\n/* 8 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor toolbar module\r\n\t *\r\n\t * Contains:\r\n\t * - Inline toolbox\r\n\t * - Toolbox within plus button\r\n\t * - Settings section\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (toolbar) {\n\t\n\t var editor = codex.editor;\n\t\n\t toolbar.settings = __webpack_require__(9);\n\t toolbar.inline = __webpack_require__(10);\n\t toolbar.toolbox = __webpack_require__(11);\n\t\n\t /**\r\n\t * Margin between focused node and toolbar\r\n\t */\n\t toolbar.defaultToolbarHeight = 49;\n\t\n\t toolbar.defaultOffset = 34;\n\t\n\t toolbar.opened = false;\n\t\n\t toolbar.current = null;\n\t\n\t /**\r\n\t * @protected\r\n\t */\n\t toolbar.open = function () {\n\t\n\t if (editor.hideToolbar) {\n\t\n\t return;\n\t }\n\t\n\t editor.nodes.toolbar.classList.add('opened');\n\t this.opened = true;\n\t };\n\t\n\t /**\r\n\t * @protected\r\n\t */\n\t toolbar.close = function () {\n\t\n\t editor.nodes.toolbar.classList.remove('opened');\n\t\n\t toolbar.opened = false;\n\t toolbar.current = null;\n\t\n\t for (var button in editor.nodes.toolbarButtons) {\n\t\n\t editor.nodes.toolbarButtons[button].classList.remove('selected');\n\t }\n\t\n\t /** Close toolbox when toolbar is not displayed */\n\t editor.toolbar.toolbox.close();\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t toolbar.toggle = function () {\n\t\n\t if (!this.opened) {\n\t\n\t this.open();\n\t } else {\n\t\n\t this.close();\n\t }\n\t };\n\t\n\t toolbar.hidePlusButton = function () {\n\t\n\t editor.nodes.plusButton.classList.add('hide');\n\t };\n\t\n\t toolbar.showPlusButton = function () {\n\t\n\t editor.nodes.plusButton.classList.remove('hide');\n\t };\n\t\n\t /**\r\n\t * Moving toolbar to the specified node\r\n\t */\n\t toolbar.move = function () {\n\t\n\t /** Close Toolbox when we move toolbar */\n\t editor.toolbar.toolbox.close();\n\t\n\t if (!editor.content.currentNode) {\n\t\n\t return;\n\t }\n\t\n\t var newYCoordinate = editor.content.currentNode.offsetTop - editor.toolbar.defaultToolbarHeight / 2 + editor.toolbar.defaultOffset;\n\t\n\t editor.nodes.toolbar.style.transform = 'translate3D(0, ' + Math.floor(newYCoordinate) + 'px, 0)';\n\t\n\t /** Close trash actions */\n\t editor.toolbar.settings.hideRemoveActions();\n\t };\n\t\n\t return toolbar;\n\t}({});\n\n/***/ },\n/* 9 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Toolbar settings\r\n\t *\r\n\t * @version 1.0.4\r\n\t */\n\t\n\tmodule.exports = function (settings) {\n\t\n\t var editor = codex.editor;\n\t\n\t settings.opened = false;\n\t\n\t settings.setting = null;\n\t settings.actions = null;\n\t\n\t settings.cover = null;\n\t\n\t /**\r\n\t * Append and open settings\r\n\t */\n\t settings.open = function (toolType) {\n\t\n\t /**\r\n\t * Append settings content\r\n\t * It's stored in tool.settings\r\n\t */\n\t if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings) {\n\t\n\t editor.core.log('Plugin \\xAB' + toolType + '\\xBB has no settings', 'warn');\n\t // editor.nodes.pluginSettings.innerHTML = `Плагин «${toolType}» не имеет настроек`;\n\t } else {\n\t\n\t /**\r\n\t * Draw settings block\r\n\t */\n\t var settingsBlock = editor.tools[toolType].makeSettings();\n\t\n\t editor.nodes.pluginSettings.appendChild(settingsBlock);\n\t }\n\t\n\t /** Open settings block */\n\t editor.nodes.blockSettings.classList.add('opened');\n\t editor.toolbar.settings.addDefaultSettings();\n\t this.opened = true;\n\t };\n\t\n\t /**\r\n\t * Close and clear settings\r\n\t */\n\t settings.close = function () {\n\t\n\t editor.nodes.blockSettings.classList.remove('opened');\n\t editor.nodes.pluginSettings.innerHTML = '';\n\t\n\t this.opened = false;\n\t };\n\t\n\t /**\r\n\t * @param {string} toolType - plugin type\r\n\t */\n\t settings.toggle = function (toolType) {\n\t\n\t if (!this.opened) {\n\t\n\t this.open(toolType);\n\t editor.anchors.settingsOpened(editor.content.currentNode);\n\t } else {\n\t\n\t this.close();\n\t }\n\t };\n\t\n\t /**\r\n\t * This function adds default core settings\r\n\t */\n\t settings.addDefaultSettings = function () {\n\t\n\t /** list of default settings */\n\t var feedModeToggler, anchorInput;\n\t\n\t /** Clear block and append initialized settings */\n\t editor.nodes.defaultSettings.innerHTML = '';\n\t\n\t /** Init all default setting buttons */\n\t feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();\n\t anchorInput = editor.toolbar.settings.makeAnchorInput();\n\t\n\t /**\r\n\t * Fill defaultSettings\r\n\t */\n\t\n\t /**\r\n\t * Input for anchor for block\r\n\t */\n\t editor.nodes.defaultSettings.appendChild(anchorInput);\n\t\n\t /**\r\n\t * Button that enables/disables Feed-mode\r\n\t * Feed-mode means that block will be showed in articles-feed like cover\r\n\t */\n\t editor.nodes.defaultSettings.appendChild(feedModeToggler);\n\t };\n\t\n\t /**\r\n\t * Cover setting.\r\n\t * This tune highlights block, so that it may be used for showing target block on main page\r\n\t * Draw different setting when block is marked for main page\r\n\t * If TRUE, then we show button that removes this selection\r\n\t * Also defined setting \"Click\" events will be listened and have separate callbacks\r\n\t *\r\n\t * @return {Element} node/button that we place in default settings block\r\n\t */\n\t settings.makeFeedModeToggler = function () {\n\t\n\t var isFeedModeActivated = editor.toolbar.settings.isFeedModeActivated(),\n\t setting,\n\t data;\n\t\n\t if (!isFeedModeActivated) {\n\t\n\t data = {\n\t innerHTML: '<i class=\"ce-icon-newspaper\"></i>Вывести в ленте'\n\t };\n\t } else {\n\t\n\t data = {\n\t innerHTML: '<i class=\"ce-icon-newspaper\"></i>Не выводить в ленте'\n\t };\n\t }\n\t\n\t setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\n\t editor.listeners.add(setting, 'click', editor.toolbar.settings.updateFeedMode, false);\n\t\n\t return setting;\n\t };\n\t\n\t /**\r\n\t * Updates Feed-mode\r\n\t */\n\t settings.updateFeedMode = function () {\n\t\n\t var currentNode = editor.content.currentNode;\n\t\n\t currentNode.classList.toggle(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t settings.isFeedModeActivated = function () {\n\t\n\t var currentBlock = editor.content.currentNode;\n\t\n\t if (currentBlock) {\n\t\n\t return currentBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t } else {\n\t\n\t return false;\n\t }\n\t };\n\t\n\t settings.makeAnchorInput = function () {\n\t\n\t var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),\n\t hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),\n\t anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });\n\t\n\t editor.listeners.add(anchor, 'keydown', editor.anchors.keyDownOnAnchorInput);\n\t editor.listeners.add(anchor, 'keyup', editor.anchors.keyUpOnAnchorInput);\n\t editor.listeners.add(anchor, 'input', editor.anchors.anchorChanged);\n\t editor.listeners.add(anchor, 'blur', editor.anchors.anchorChanged);\n\t\n\t anchorWrapper.appendChild(hash);\n\t anchorWrapper.appendChild(anchor);\n\t\n\t editor.anchors.input = anchor;\n\t\n\t return anchorWrapper;\n\t };\n\t\n\t /**\r\n\t * Here we will draw buttons and add listeners to components\r\n\t */\n\t settings.makeRemoveBlockButton = function () {\n\t\n\t var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}),\n\t settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML: '<i class=\"ce-icon-trash\"></i>' }),\n\t actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\n\t confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent: 'Удалить блок' }),\n\t cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent: 'Отмена' });\n\t\n\t editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\n\t\n\t editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\n\t\n\t editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\n\t\n\t actionWrapper.appendChild(confirmAction);\n\t actionWrapper.appendChild(cancelAction);\n\t\n\t removeBlockWrapper.appendChild(settingButton);\n\t removeBlockWrapper.appendChild(actionWrapper);\n\t\n\t /** Save setting */\n\t editor.toolbar.settings.setting = settingButton;\n\t editor.toolbar.settings.actions = actionWrapper;\n\t\n\t return removeBlockWrapper;\n\t };\n\t\n\t settings.removeButtonClicked = function () {\n\t\n\t var action = editor.toolbar.settings.actions;\n\t\n\t if (action.classList.contains('opened')) {\n\t\n\t editor.toolbar.settings.hideRemoveActions();\n\t } else {\n\t\n\t editor.toolbar.settings.showRemoveActions();\n\t }\n\t\n\t editor.toolbar.toolbox.close();\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t settings.cancelRemovingRequest = function () {\n\t\n\t editor.toolbar.settings.actions.classList.remove('opened');\n\t };\n\t\n\t settings.confirmRemovingRequest = function () {\n\t\n\t var currentBlock = editor.content.currentNode,\n\t firstLevelBlocksCount;\n\t\n\t currentBlock.remove();\n\t\n\t firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\t\n\t /**\r\n\t * If all blocks are removed\r\n\t */\n\t if (firstLevelBlocksCount === 0) {\n\t\n\t /** update currentNode variable */\n\t editor.content.currentNode = null;\n\t\n\t /** Inserting new empty initial block */\n\t editor.ui.addInitialBlock();\n\t }\n\t\n\t editor.ui.saveInputs();\n\t\n\t editor.toolbar.close();\n\t };\n\t\n\t settings.showRemoveActions = function () {\n\t\n\t editor.toolbar.settings.actions.classList.add('opened');\n\t };\n\t\n\t settings.hideRemoveActions = function () {\n\t\n\t editor.toolbar.settings.actions.classList.remove('opened');\n\t };\n\t\n\t return settings;\n\t}({});\n\n/***/ },\n/* 10 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Inline toolbar\r\n\t *\r\n\t * Contains from tools:\r\n\t * Bold, Italic, Underline and Anchor\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (inline) {\n\t\n\t var editor = codex.editor;\n\t\n\t inline.buttonsOpened = null;\n\t inline.actionsOpened = null;\n\t inline.wrappersOffset = null;\n\t\n\t /**\r\n\t * saving selection that need for execCommand for styling\r\n\t *\r\n\t */\n\t inline.storedSelection = null;\n\t\n\t /**\r\n\t * @protected\r\n\t *\r\n\t * Open inline toobar\r\n\t */\n\t inline.show = function () {\n\t\n\t var currentNode = editor.content.currentNode,\n\t tool = currentNode.dataset.tool,\n\t plugin;\n\t\n\t /**\r\n\t * tool allowed to open inline toolbar\r\n\t */\n\t plugin = editor.tools[tool];\n\t\n\t if (!plugin.showInlineToolbar) return;\n\t\n\t var selectedText = inline.getSelectionText(),\n\t toolbar = editor.nodes.inlineToolbar.wrapper;\n\t\n\t if (selectedText.length > 0) {\n\t\n\t /** Move toolbar and open */\n\t editor.toolbar.inline.move();\n\t\n\t /** Open inline toolbar */\n\t toolbar.classList.add('opened');\n\t\n\t /** show buttons of inline toolbar */\n\t editor.toolbar.inline.showButtons();\n\t }\n\t };\n\t\n\t /**\r\n\t * @protected\r\n\t *\r\n\t * Closes inline toolbar\r\n\t */\n\t inline.close = function () {\n\t\n\t var toolbar = editor.nodes.inlineToolbar.wrapper;\n\t\n\t toolbar.classList.remove('opened');\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Moving toolbar\r\n\t */\n\t inline.move = function () {\n\t\n\t if (!this.wrappersOffset) {\n\t\n\t this.wrappersOffset = this.getWrappersOffset();\n\t }\n\t\n\t var coords = this.getSelectionCoords(),\n\t defaultOffset = 0,\n\t toolbar = editor.nodes.inlineToolbar.wrapper,\n\t newCoordinateX,\n\t newCoordinateY;\n\t\n\t if (toolbar.offsetHeight === 0) {\n\t\n\t defaultOffset = 40;\n\t }\n\t\n\t newCoordinateX = coords.x - this.wrappersOffset.left;\n\t newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;\n\t\n\t toolbar.style.transform = 'translate3D(' + Math.floor(newCoordinateX) + 'px, ' + Math.floor(newCoordinateY) + 'px, 0)';\n\t\n\t /** Close everything */\n\t editor.toolbar.inline.closeButtons();\n\t editor.toolbar.inline.closeAction();\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Tool Clicked\r\n\t */\n\t\n\t inline.toolClicked = function (event, type) {\n\t\n\t /**\r\n\t * For simple tools we use default browser function\r\n\t * For more complicated tools, we should write our own behavior\r\n\t */\n\t switch (type) {\n\t case 'createLink':\n\t editor.toolbar.inline.createLinkAction(event, type);break;\n\t default:\n\t editor.toolbar.inline.defaultToolAction(type);break;\n\t }\n\t\n\t /**\r\n\t * highlight buttons\r\n\t * after making some action\r\n\t */\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Saving wrappers offset in DOM\r\n\t */\n\t inline.getWrappersOffset = function () {\n\t\n\t var wrapper = editor.nodes.wrapper,\n\t offset = this.getOffset(wrapper);\n\t\n\t this.wrappersOffset = offset;\n\t return offset;\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Calculates offset of DOM element\r\n\t *\r\n\t * @param el\r\n\t * @returns {{top: number, left: number}}\r\n\t */\n\t inline.getOffset = function (el) {\n\t\n\t var _x = 0;\n\t var _y = 0;\n\t\n\t while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {\n\t\n\t _x += el.offsetLeft + el.clientLeft;\n\t _y += el.offsetTop + el.clientTop;\n\t el = el.offsetParent;\n\t }\n\t return { top: _y, left: _x };\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Calculates position of selected text\r\n\t * @returns {{x: number, y: number}}\r\n\t */\n\t inline.getSelectionCoords = function () {\n\t\n\t var sel = document.selection,\n\t range;\n\t var x = 0,\n\t y = 0;\n\t\n\t if (sel) {\n\t\n\t if (sel.type != 'Control') {\n\t\n\t range = sel.createRange();\n\t range.collapse(true);\n\t x = range.boundingLeft;\n\t y = range.boundingTop;\n\t }\n\t } else if (window.getSelection) {\n\t\n\t sel = window.getSelection();\n\t\n\t if (sel.rangeCount) {\n\t\n\t range = sel.getRangeAt(0).cloneRange();\n\t if (range.getClientRects) {\n\t\n\t range.collapse(true);\n\t var rect = range.getClientRects()[0];\n\t\n\t if (!rect) {\n\t\n\t return;\n\t }\n\t\n\t x = rect.left;\n\t y = rect.top;\n\t }\n\t }\n\t }\n\t return { x: x, y: y };\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Returns selected text as String\r\n\t * @returns {string}\r\n\t */\n\t inline.getSelectionText = function () {\n\t\n\t var selectedText = '';\n\t\n\t // all modern browsers and IE9+\n\t if (window.getSelection) {\n\t\n\t selectedText = window.getSelection().toString();\n\t }\n\t\n\t return selectedText;\n\t };\n\t\n\t /** Opens buttons block */\n\t inline.showButtons = function () {\n\t\n\t var buttons = editor.nodes.inlineToolbar.buttons;\n\t\n\t buttons.classList.add('opened');\n\t\n\t editor.toolbar.inline.buttonsOpened = true;\n\t\n\t /** highlight buttons */\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\t };\n\t\n\t /** Makes buttons disappear */\n\t inline.closeButtons = function () {\n\t\n\t var buttons = editor.nodes.inlineToolbar.buttons;\n\t\n\t buttons.classList.remove('opened');\n\t\n\t editor.toolbar.inline.buttonsOpened = false;\n\t };\n\t\n\t /** Open buttons defined action if exist */\n\t inline.showActions = function () {\n\t\n\t var action = editor.nodes.inlineToolbar.actions;\n\t\n\t action.classList.add('opened');\n\t\n\t editor.toolbar.inline.actionsOpened = true;\n\t };\n\t\n\t /** Close actions block */\n\t inline.closeAction = function () {\n\t\n\t var action = editor.nodes.inlineToolbar.actions;\n\t\n\t action.innerHTML = '';\n\t action.classList.remove('opened');\n\t editor.toolbar.inline.actionsOpened = false;\n\t };\n\t\n\t /**\r\n\t * Callback for keydowns in inline toolbar \"Insert link...\" input\r\n\t */\n\t var inlineToolbarAnchorInputKeydown_ = function inlineToolbarAnchorInputKeydown_(event) {\n\t\n\t if (event.keyCode != editor.core.keys.ENTER) {\n\t\n\t return;\n\t }\n\t\n\t var editable = editor.content.currentNode,\n\t storedSelection = editor.toolbar.inline.storedSelection;\n\t\n\t editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\t editor.toolbar.inline.setAnchor(this.value);\n\t\n\t /**\r\n\t * Preventing events that will be able to happen\r\n\t */\n\t event.preventDefault();\n\t event.stopImmediatePropagation();\n\t\n\t editor.toolbar.inline.clearRange();\n\t };\n\t\n\t /** Action for link creation or for setting anchor */\n\t inline.createLinkAction = function (event) {\n\t\n\t var isActive = this.isLinkActive();\n\t\n\t var editable = editor.content.currentNode,\n\t storedSelection = editor.toolbar.inline.saveSelection(editable);\n\t\n\t /** Save globally selection */\n\t editor.toolbar.inline.storedSelection = storedSelection;\n\t\n\t if (isActive) {\n\t\n\t /**\r\n\t * Changing stored selection. if we want to remove anchor from word\r\n\t * we should remove anchor from whole word, not only selected part.\r\n\t * The solution is than we get the length of current link\r\n\t * Change start position to - end of selection minus length of anchor\r\n\t */\n\t editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\t\n\t editor.toolbar.inline.defaultToolAction('unlink');\n\t } else {\n\t\n\t /** Create input and close buttons */\n\t var action = editor.draw.inputForLink();\n\t\n\t editor.nodes.inlineToolbar.actions.appendChild(action);\n\t\n\t editor.toolbar.inline.closeButtons();\n\t editor.toolbar.inline.showActions();\n\t\n\t /**\r\n\t * focus to input\r\n\t * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\r\n\t * Prevents event after showing input and when we need to focus an input which is in unexisted form\r\n\t */\n\t action.focus();\n\t event.preventDefault();\n\t\n\t /** Callback to link action */\n\t editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);\n\t }\n\t };\n\t\n\t inline.isLinkActive = function () {\n\t\n\t var isActive = false;\n\t\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\n\t\n\t var dataType = tool.dataset.type;\n\t\n\t if (dataType == 'link' && tool.classList.contains('hightlighted')) {\n\t\n\t isActive = true;\n\t }\n\t });\n\t\n\t return isActive;\n\t };\n\t\n\t /** default action behavior of tool */\n\t inline.defaultToolAction = function (type) {\n\t\n\t document.execCommand(type, false, null);\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Sets URL\r\n\t *\r\n\t * @param {String} url - URL\r\n\t */\n\t inline.setAnchor = function (url) {\n\t\n\t document.execCommand('createLink', false, url);\n\t\n\t /** Close after URL inserting */\n\t editor.toolbar.inline.closeAction();\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Saves selection\r\n\t */\n\t inline.saveSelection = function (containerEl) {\n\t\n\t var range = window.getSelection().getRangeAt(0),\n\t preSelectionRange = range.cloneRange(),\n\t start;\n\t\n\t preSelectionRange.selectNodeContents(containerEl);\n\t preSelectionRange.setEnd(range.startContainer, range.startOffset);\n\t\n\t start = preSelectionRange.toString().length;\n\t\n\t return {\n\t start: start,\n\t end: start + range.toString().length\n\t };\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Sets to previous selection (Range)\r\n\t *\r\n\t * @param {Element} containerEl - editable element where we restore range\r\n\t * @param {Object} savedSel - range basic information to restore\r\n\t */\n\t inline.restoreSelection = function (containerEl, savedSel) {\n\t\n\t var range = document.createRange(),\n\t charIndex = 0;\n\t\n\t range.setStart(containerEl, 0);\n\t range.collapse(true);\n\t\n\t var nodeStack = [containerEl],\n\t node,\n\t foundStart = false,\n\t stop = false,\n\t nextCharIndex;\n\t\n\t while (!stop && (node = nodeStack.pop())) {\n\t\n\t if (node.nodeType == 3) {\n\t\n\t nextCharIndex = charIndex + node.length;\n\t\n\t if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\n\t\n\t range.setStart(node, savedSel.start - charIndex);\n\t foundStart = true;\n\t }\n\t if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\n\t\n\t range.setEnd(node, savedSel.end - charIndex);\n\t stop = true;\n\t }\n\t charIndex = nextCharIndex;\n\t } else {\n\t\n\t var i = node.childNodes.length;\n\t\n\t while (i--) {\n\t\n\t nodeStack.push(node.childNodes[i]);\n\t }\n\t }\n\t }\n\t\n\t var sel = window.getSelection();\n\t\n\t sel.removeAllRanges();\n\t sel.addRange(range);\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Removes all ranges from window selection\r\n\t */\n\t inline.clearRange = function () {\n\t\n\t var selection = window.getSelection();\n\t\n\t selection.removeAllRanges();\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * sets or removes hightlight\r\n\t */\n\t inline.hightlight = function (tool) {\n\t\n\t var dataType = tool.dataset.type;\n\t\n\t if (document.queryCommandState(dataType)) {\n\t\n\t editor.toolbar.inline.setButtonHighlighted(tool);\n\t } else {\n\t\n\t editor.toolbar.inline.removeButtonsHighLight(tool);\n\t }\n\t\n\t /**\r\n\t *\r\n\t * hightlight for anchors\r\n\t */\n\t var selection = window.getSelection(),\n\t tag = selection.anchorNode.parentNode;\n\t\n\t if (tag.tagName == 'A' && dataType == 'link') {\n\t\n\t editor.toolbar.inline.setButtonHighlighted(tool);\n\t }\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Mark button if text is already executed\r\n\t */\n\t inline.setButtonHighlighted = function (button) {\n\t\n\t button.classList.add('hightlighted');\n\t\n\t /** At link tool we also change icon */\n\t if (button.dataset.type == 'link') {\n\t\n\t var icon = button.childNodes[0];\n\t\n\t icon.classList.remove('ce-icon-link');\n\t icon.classList.add('ce-icon-unlink');\n\t }\n\t };\n\t\n\t /**\r\n\t * @private\r\n\t *\r\n\t * Removes hightlight\r\n\t */\n\t inline.removeButtonsHighLight = function (button) {\n\t\n\t button.classList.remove('hightlighted');\n\t\n\t /** At link tool we also change icon */\n\t if (button.dataset.type == 'link') {\n\t\n\t var icon = button.childNodes[0];\n\t\n\t icon.classList.remove('ce-icon-unlink');\n\t icon.classList.add('ce-icon-link');\n\t }\n\t };\n\t\n\t return inline;\n\t}({});\n\n/***/ },\n/* 11 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor toolbox\r\n\t *\r\n\t * All tools be able to appended here\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (toolbox) {\n\t\n\t var editor = codex.editor;\n\t\n\t toolbox.opened = false;\n\t\n\t /** Shows toolbox */\n\t toolbox.open = function () {\n\t\n\t /** Close setting if toolbox is opened */\n\t if (editor.toolbar.settings.opened) {\n\t\n\t editor.toolbar.settings.close();\n\t }\n\t\n\t /** display toolbox */\n\t editor.nodes.toolbox.classList.add('opened');\n\t\n\t /** Animate plus button */\n\t editor.nodes.plusButton.classList.add('clicked');\n\t\n\t /** toolbox state */\n\t editor.toolbar.toolbox.opened = true;\n\t };\n\t\n\t /** Closes toolbox */\n\t toolbox.close = function () {\n\t\n\t /** Makes toolbox disapear */\n\t editor.nodes.toolbox.classList.remove('opened');\n\t\n\t /** Rotate plus button */\n\t editor.nodes.plusButton.classList.remove('clicked');\n\t\n\t /** toolbox state */\n\t editor.toolbar.toolbox.opened = false;\n\t };\n\t\n\t toolbox.leaf = function () {\n\t\n\t var currentTool = editor.toolbar.current,\n\t tools = Object.keys(editor.tools),\n\t barButtons = editor.nodes.toolbarButtons,\n\t nextToolIndex = 0,\n\t toolToSelect = void 0,\n\t visibleTool = void 0,\n\t tool = void 0;\n\t\n\t if (!currentTool) {\n\t\n\t /** Get first tool from object*/\n\t for (tool in editor.tools) {\n\t\n\t if (editor.tools[tool].displayInToolbox) {\n\t\n\t break;\n\t }\n\t\n\t nextToolIndex++;\n\t }\n\t } else {\n\t\n\t nextToolIndex = tools.indexOf(currentTool) + 1;\n\t visibleTool = tools[nextToolIndex];\n\t\n\t while (!editor.tools[visibleTool].displayInToolbox) {\n\t\n\t nextToolIndex++;\n\t visibleTool = tools[nextToolIndex];\n\t\n\t if (nextToolIndex == tools.length) {\n\t\n\t nextToolIndex = 0;\n\t visibleTool = tools[nextToolIndex];\n\t }\n\t }\n\t }\n\t\n\t toolToSelect = tools[nextToolIndex];\n\t\n\t for (var button in barButtons) {\n\t\n\t barButtons[button].classList.remove('selected');\n\t }\n\t\n\t barButtons[toolToSelect].classList.add('selected');\n\t editor.toolbar.current = toolToSelect;\n\t };\n\t\n\t /**\r\n\t * Transforming selected node type into selected toolbar element type\r\n\t * @param {event} event\r\n\t */\n\t toolbox.toolClicked = function (event) {\n\t\n\t /**\r\n\t * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty\r\n\t */\n\t var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],\n\t tool = editor.tools[editor.toolbar.current],\n\t workingNode = editor.content.currentNode,\n\t currentInputIndex = editor.caret.inputIndex,\n\t newBlockContent,\n\t appendCallback,\n\t blockData;\n\t\n\t /** Make block from plugin */\n\t newBlockContent = tool.render();\n\t\n\t /** information about block */\n\t blockData = {\n\t block: newBlockContent,\n\t type: tool.type,\n\t stretched: false\n\t };\n\t\n\t if (workingNode && UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 && workingNode.textContent.trim() === '') {\n\t\n\t /** Replace current block */\n\t editor.content.switchBlock(workingNode, newBlockContent, tool.type);\n\t } else {\n\t\n\t /** Insert new Block from plugin */\n\t editor.content.insertBlock(blockData);\n\t\n\t /** increase input index */\n\t currentInputIndex++;\n\t }\n\t\n\t /** Fire tool append callback */\n\t appendCallback = tool.appendCallback;\n\t\n\t if (appendCallback && typeof appendCallback == 'function') {\n\t\n\t appendCallback.call(event);\n\t }\n\t\n\t window.setTimeout(function () {\n\t\n\t /** Set caret to current block */\n\t editor.caret.setToBlock(currentInputIndex);\n\t }, 10);\n\t\n\t /**\r\n\t * Changing current Node\r\n\t */\n\t editor.content.workingNodeChanged();\n\t\n\t /**\r\n\t * Move toolbar when node is changed\r\n\t */\n\t editor.toolbar.move();\n\t };\n\t\n\t return toolbox;\n\t}({});\n\n/***/ },\n/* 12 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor callbacks module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.3.7\r\n\t */\n\t\n\tmodule.exports = function (callbacks) {\n\t\n\t var editor = codex.editor;\n\t\n\t callbacks.globalKeydown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.redactorKeyDown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.TAB:\n\t editor.callback.tabKeyPressed(event);break;\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressedOnRedactorZone(event);break;\n\t case editor.core.keys.ESC:\n\t editor.callback.escapeKeyPressed(event);break;\n\t default:\n\t editor.callback.defaultKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.globalKeyup = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.UP:\n\t case editor.core.keys.LEFT:\n\t case editor.core.keys.RIGHT:\n\t case editor.core.keys.DOWN:\n\t editor.callback.arrowKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.tabKeyPressed = function (event) {\n\t\n\t var blockIsEmpty = !editor.content.currentNode.textContent.trim();\n\t\n\t if (!blockIsEmpty) {\n\t\n\t return;\n\t }\n\t\n\t if (!editor.toolbar.opened) {\n\t\n\t editor.toolbar.open();\n\t }\n\t\n\t if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\t\n\t editor.toolbar.toolbox.open();\n\t } else {\n\t\n\t editor.toolbar.toolbox.leaf();\n\t }\n\t\n\t event.preventDefault();\n\t };\n\t\n\t /**\r\n\t * @param {Event} event\r\n\t */\n\t callbacks.enterKeyPressed = function () {\n\t\n\t if (editor.content.editorAreaHightlighted) {\n\t\n\t /**\r\n\t * it means that we lose input index, saved index before is not correct\r\n\t * therefore we need to set caret when we insert new block\r\n\t */\n\t editor.caret.inputIndex = -1;\n\t\n\t editor.callback.enterPressedOnBlock();\n\t }\n\t };\n\t\n\t /**\r\n\t * ENTER key handler\r\n\t * Makes new paragraph block\r\n\t */\n\t callbacks.enterKeyPressedOnRedactorZone = function (event) {\n\t\n\t if (event.target.contentEditable == 'true') {\n\t\n\t /** Update input index */\n\t editor.caret.saveCurrentInputIndex();\n\t }\n\t\n\t var currentInputIndex = editor.caret.getCurrentInputIndex() || 0,\n\t workingNode = editor.content.currentNode,\n\t tool = workingNode.dataset.tool,\n\t isEnterPressedOnToolbar = editor.toolbar.opened && editor.toolbar.current && event.target == editor.state.inputs[currentInputIndex];\n\t\n\t /** The list of tools which needs the default browser behaviour */\n\t var enableLineBreaks = editor.tools[tool].enableLineBreaks;\n\t\n\t /** This type of block creates when enter is pressed */\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\t\n\t /**\r\n\t * When toolbar is opened, select tool instead of making new paragraph\r\n\t */\n\t if (isEnterPressedOnToolbar) {\n\t\n\t event.preventDefault();\n\t\n\t editor.toolbar.toolbox.toolClicked(event);\n\t\n\t editor.toolbar.close();\n\t\n\t /**\r\n\t * Stop other listeners callback executions\r\n\t */\n\t event.stopPropagation();\n\t event.stopImmediatePropagation();\n\t\n\t return;\n\t }\n\t\n\t /**\r\n\t * Allow paragraph lineBreaks with shift enter\r\n\t * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation\r\n\t */\n\t if (event.shiftKey || enableLineBreaks) {\n\t\n\t event.stopPropagation();\n\t event.stopImmediatePropagation();\n\t return;\n\t }\n\t\n\t var currentSelection = window.getSelection(),\n\t currentSelectedNode = currentSelection.anchorNode,\n\t caretAtTheEndOfText = editor.caret.position.atTheEnd(),\n\t isTextNodeHasParentBetweenContenteditable = false;\n\t\n\t /**\r\n\t * Allow making new <p> in same block by SHIFT+ENTER and forbids to prevent default browser behaviour\r\n\t */\n\t if (event.shiftKey && !enableLineBreaks) {\n\t\n\t editor.callback.enterPressedOnBlock(editor.content.currentBlock, event);\n\t event.preventDefault();\n\t return;\n\t }\n\t\n\t /**\r\n\t * Workaround situation when caret at the Text node that has some wrapper Elements\r\n\t * Split block cant handle this.\r\n\t * We need to save default behavior\r\n\t */\n\t isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true';\n\t\n\t /**\r\n\t * Split blocks when input has several nodes and caret placed in textNode\r\n\t */\n\t if (currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT && !isTextNodeHasParentBetweenContenteditable && !caretAtTheEndOfText) {\n\t\n\t event.preventDefault();\n\t\n\t editor.core.log('Splitting Text node...');\n\t\n\t editor.content.splitBlock(currentInputIndex);\n\t\n\t /** Show plus button when next input after split is empty*/\n\t if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) {\n\t\n\t editor.toolbar.showPlusButton();\n\t }\n\t } else {\n\t\n\t var islastNode = editor.content.isLastNode(currentSelectedNode);\n\t\n\t if (islastNode && caretAtTheEndOfText) {\n\t\n\t event.preventDefault();\n\t event.stopPropagation();\n\t event.stopImmediatePropagation();\n\t\n\t editor.core.log('ENTER clicked in last textNode. Create new BLOCK');\n\t\n\t editor.content.insertBlock({\n\t type: NEW_BLOCK_TYPE,\n\t block: editor.tools[NEW_BLOCK_TYPE].render()\n\t }, true);\n\t\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t\n\t /** Show plus button with empty block */\n\t editor.toolbar.showPlusButton();\n\t }\n\t }\n\t\n\t /** get all inputs after new appending block */\n\t editor.ui.saveInputs();\n\t };\n\t\n\t callbacks.escapeKeyPressed = function (event) {\n\t\n\t /** Close all toolbar */\n\t editor.toolbar.close();\n\t\n\t /** Close toolbox */\n\t editor.toolbar.toolbox.close();\n\t\n\t event.preventDefault();\n\t };\n\t\n\t /**\r\n\t * @param {Event} event\r\n\t */\n\t callbacks.arrowKeyPressed = function () {\n\t\n\t editor.content.workingNodeChanged();\n\t\n\t /* Closing toolbar */\n\t editor.toolbar.close();\n\t editor.toolbar.move();\n\t };\n\t\n\t /**\r\n\t * @param {Event} event\r\n\t */\n\t callbacks.defaultKeyPressed = function () {\n\t\n\t editor.toolbar.close();\n\t\n\t if (!editor.toolbar.inline.actionsOpened) {\n\t\n\t editor.toolbar.inline.close();\n\t editor.content.clearMark();\n\t }\n\t };\n\t\n\t callbacks.redactorClicked = function (event) {\n\t\n\t callbacks.detectWhenClickedOnFirstLevelBlockArea();\n\t\n\t editor.content.workingNodeChanged(event.target);\n\t\n\t editor.ui.saveInputs();\n\t\n\t var selectedText = editor.toolbar.inline.getSelectionText(),\n\t firstLevelBlock;\n\t\n\t /**\r\n\t * If selection range took off, then we hide inline toolbar\r\n\t */\n\t if (selectedText.length === 0) {\n\t\n\t editor.toolbar.inline.close();\n\t }\n\t\n\t /** Update current input index in memory when caret focused into existed input */\n\t if (event.target.contentEditable == 'true') {\n\t\n\t editor.caret.saveCurrentInputIndex();\n\t }\n\t\n\t if (editor.content.currentNode === null) {\n\t\n\t /**\r\n\t * If inputs in redactor does not exits, then we put input index 0 not -1\r\n\t */\n\t var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0;\n\t\n\t /** If we have any inputs */\n\t if (editor.state.inputs.length) {\n\t\n\t /**\r\n\t * @todo Refactor\r\n\t */\n\t\n\t /** getting firstlevel parent of input */\n\t firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);\n\t }\n\t\n\t /** If input is empty, then we set caret to the last input */\n\t if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {\n\t\n\t editor.caret.setToBlock(indexOfLastInput);\n\t } else {\n\t\n\t /** Create new input when caret clicked in redactors area */\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\t\n\t editor.content.insertBlock({\n\t type: NEW_BLOCK_TYPE,\n\t block: editor.tools[NEW_BLOCK_TYPE].render()\n\t });\n\t\n\t /** If there is no inputs except inserted */\n\t if (editor.state.inputs.length === 1) {\n\t\n\t editor.caret.setToBlock(indexOfLastInput);\n\t } else {\n\t\n\t /** Set caret to this appended input */\n\t editor.caret.setToNextBlock(indexOfLastInput);\n\t }\n\t }\n\t\n\t /**\r\n\t * Move toolbar to the right position and open\r\n\t */\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t } else {\n\t\n\t /**\r\n\t * Move toolbar to the new position and open\r\n\t */\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t\n\t /** Close all panels */\n\t editor.toolbar.settings.close();\n\t editor.toolbar.toolbox.close();\n\t }\n\t\n\t var inputIsEmpty = !editor.content.currentNode.textContent.trim(),\n\t currentNodeType = editor.content.currentNode.dataset.tool,\n\t isInitialType = currentNodeType == editor.settings.initialBlockPlugin;\n\t\n\t /** Hide plus buttons */\n\t editor.toolbar.hidePlusButton();\n\t\n\t if (!inputIsEmpty) {\n\t\n\t /** Mark current block */\n\t editor.content.markBlock();\n\t }\n\t\n\t if (isInitialType && inputIsEmpty) {\n\t\n\t /** Show plus button */\n\t editor.toolbar.showPlusButton();\n\t }\n\t };\n\t\n\t /**\r\n\t * This method allows to define, is caret in contenteditable element or not.\r\n\t * Otherwise, if we get TEXT node from range container, that will means we have input index.\r\n\t * In this case we use default browsers behaviour (if plugin allows that) or overwritten action.\r\n\t * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always\r\n\t * specifies to the first-level block. Other cases we just ignore.\r\n\t */\n\t callbacks.detectWhenClickedOnFirstLevelBlockArea = function () {\n\t\n\t var selection = window.getSelection(),\n\t anchorNode = selection.anchorNode,\n\t flag = false;\n\t\n\t if (selection.rangeCount === 0) {\n\t\n\t editor.content.editorAreaHightlighted = true;\n\t } else {\n\t\n\t if (!editor.core.isDomNode(anchorNode)) {\n\t\n\t anchorNode = anchorNode.parentNode;\n\t }\n\t\n\t /** Already founded, without loop */\n\t if (anchorNode.contentEditable == 'true') {\n\t\n\t flag = true;\n\t }\n\t\n\t while (anchorNode.contentEditable != 'true') {\n\t\n\t anchorNode = anchorNode.parentNode;\n\t\n\t if (anchorNode.contentEditable == 'true') {\n\t\n\t flag = true;\n\t }\n\t\n\t if (anchorNode == document.body) {\n\t\n\t break;\n\t }\n\t }\n\t\n\t /** If editable element founded, flag is \"TRUE\", Therefore we return \"FALSE\" */\n\t editor.content.editorAreaHightlighted = flag ? false : true;\n\t }\n\t };\n\t\n\t /**\r\n\t * Toolbar button click handler\r\n\t * @param this - cursor to the button\r\n\t */\n\t callbacks.toolbarButtonClicked = function (event) {\n\t\n\t var button = this;\n\t\n\t editor.toolbar.current = button.dataset.type;\n\t\n\t editor.toolbar.toolbox.toolClicked(event);\n\t editor.toolbar.close();\n\t };\n\t\n\t /** Show or Hide toolbox when plus button is clicked */\n\t callbacks.plusButtonClicked = function () {\n\t\n\t if (!editor.nodes.toolbox.classList.contains('opened')) {\n\t\n\t editor.toolbar.toolbox.open();\n\t } else {\n\t\n\t editor.toolbar.toolbox.close();\n\t }\n\t };\n\t\n\t /**\r\n\t * Block handlers for KeyDown events\r\n\t */\n\t callbacks.blockKeydown = function (event) {\n\t\n\t var block = this; // event.target input\n\t\n\t switch (event.keyCode) {\n\t\n\t case editor.core.keys.DOWN:\n\t case editor.core.keys.RIGHT:\n\t editor.callback.blockRightOrDownArrowPressed();\n\t break;\n\t\n\t case editor.core.keys.BACKSPACE:\n\t editor.callback.backspacePressed(block, event);\n\t break;\n\t\n\t case editor.core.keys.UP:\n\t case editor.core.keys.LEFT:\n\t editor.callback.blockLeftOrUpArrowPressed();\n\t break;\n\t\n\t }\n\t };\n\t\n\t /**\r\n\t * RIGHT or DOWN keydowns on block\r\n\t */\n\t callbacks.blockRightOrDownArrowPressed = function () {\n\t\n\t var selection = window.getSelection(),\n\t inputs = editor.state.inputs,\n\t focusedNode = selection.anchorNode,\n\t focusedNodeHolder;\n\t\n\t /** Check for caret existance */\n\t if (!focusedNode) {\n\t\n\t return false;\n\t }\n\t\n\t /** Looking for closest (parent) contentEditable element of focused node */\n\t while (focusedNode.contentEditable != 'true') {\n\t\n\t focusedNodeHolder = focusedNode.parentNode;\n\t focusedNode = focusedNodeHolder;\n\t }\n\t\n\t /** Input index in DOM level */\n\t var editableElementIndex = 0;\n\t\n\t while (focusedNode != inputs[editableElementIndex]) {\n\t\n\t editableElementIndex++;\n\t }\n\t\n\t /**\r\n\t * Founded contentEditable element doesn't have childs\r\n\t * Or maybe New created block\r\n\t */\n\t if (!focusedNode.textContent) {\n\t\n\t editor.caret.setToNextBlock(editableElementIndex);\n\t return;\n\t }\n\t\n\t /**\r\n\t * Do nothing when caret doesn not reaches the end of last child\r\n\t */\n\t var caretInLastChild = false,\n\t caretAtTheEndOfText = false;\n\t\n\t var lastChild, deepestTextnode;\n\t\n\t lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1];\n\t\n\t if (editor.core.isDomNode(lastChild)) {\n\t\n\t deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length);\n\t } else {\n\t\n\t deepestTextnode = lastChild;\n\t }\n\t\n\t caretInLastChild = selection.anchorNode == deepestTextnode;\n\t caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset;\n\t\n\t if (!caretInLastChild || !caretAtTheEndOfText) {\n\t\n\t editor.core.log('arrow [down|right] : caret does not reached the end');\n\t return false;\n\t }\n\t\n\t editor.caret.setToNextBlock(editableElementIndex);\n\t };\n\t\n\t /**\r\n\t * LEFT or UP keydowns on block\r\n\t */\n\t callbacks.blockLeftOrUpArrowPressed = function () {\n\t\n\t var selection = window.getSelection(),\n\t inputs = editor.state.inputs,\n\t focusedNode = selection.anchorNode,\n\t focusedNodeHolder;\n\t\n\t /** Check for caret existance */\n\t if (!focusedNode) {\n\t\n\t return false;\n\t }\n\t\n\t /**\r\n\t * LEFT or UP not at the beginning\r\n\t */\n\t if (selection.anchorOffset !== 0) {\n\t\n\t return false;\n\t }\n\t\n\t /** Looking for parent contentEditable block */\n\t while (focusedNode.contentEditable != 'true') {\n\t\n\t focusedNodeHolder = focusedNode.parentNode;\n\t focusedNode = focusedNodeHolder;\n\t }\n\t\n\t /** Input index in DOM level */\n\t var editableElementIndex = 0;\n\t\n\t while (focusedNode != inputs[editableElementIndex]) {\n\t\n\t editableElementIndex++;\n\t }\n\t\n\t /**\r\n\t * Do nothing if caret is not at the beginning of first child\r\n\t */\n\t var caretInFirstChild = false,\n\t caretAtTheBeginning = false;\n\t\n\t var firstChild, deepestTextnode;\n\t\n\t /**\r\n\t * Founded contentEditable element doesn't have childs\r\n\t * Or maybe New created block\r\n\t */\n\t if (!focusedNode.textContent) {\n\t\n\t editor.caret.setToPreviousBlock(editableElementIndex);\n\t return;\n\t }\n\t\n\t firstChild = focusedNode.childNodes[0];\n\t\n\t if (editor.core.isDomNode(firstChild)) {\n\t\n\t deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0);\n\t } else {\n\t\n\t deepestTextnode = firstChild;\n\t }\n\t\n\t caretInFirstChild = selection.anchorNode == deepestTextnode;\n\t caretAtTheBeginning = selection.anchorOffset === 0;\n\t\n\t if (caretInFirstChild && caretAtTheBeginning) {\n\t\n\t editor.caret.setToPreviousBlock(editableElementIndex);\n\t }\n\t };\n\t\n\t /**\r\n\t * Callback for enter key pressing in first-level block area\r\n\t * @param {Event} event\r\n\t */\n\t callbacks.enterPressedOnBlock = function () {\n\t\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\t\n\t editor.content.insertBlock({\n\t type: NEW_BLOCK_TYPE,\n\t block: editor.tools[NEW_BLOCK_TYPE].render()\n\t }, true);\n\t\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t };\n\t\n\t callbacks.backspacePressed = function (block, event) {\n\t\n\t var currentInputIndex = editor.caret.getCurrentInputIndex(),\n\t range,\n\t selectionLength,\n\t firstLevelBlocksCount;\n\t\n\t if (block.textContent.trim()) {\n\t\n\t range = editor.content.getRange();\n\t selectionLength = range.endOffset - range.startOffset;\n\t\n\t if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {\n\t\n\t editor.content.mergeBlocks(currentInputIndex);\n\t } else {\n\t\n\t return;\n\t }\n\t }\n\t\n\t if (!selectionLength) {\n\t\n\t block.remove();\n\t }\n\t\n\t firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\t\n\t /**\r\n\t * If all blocks are removed\r\n\t */\n\t if (firstLevelBlocksCount === 0) {\n\t\n\t /** update currentNode variable */\n\t editor.content.currentNode = null;\n\t\n\t /** Inserting new empty initial block */\n\t editor.ui.addInitialBlock();\n\t\n\t /** Updating inputs state after deleting last block */\n\t editor.ui.saveInputs();\n\t\n\t /** Set to current appended block */\n\t window.setTimeout(function () {\n\t\n\t editor.caret.setToPreviousBlock(1);\n\t }, 10);\n\t } else {\n\t\n\t if (editor.caret.inputIndex !== 0) {\n\t\n\t /** Target block is not first */\n\t editor.caret.setToPreviousBlock(editor.caret.inputIndex);\n\t } else {\n\t\n\t /** If we try to delete first block */\n\t editor.caret.setToNextBlock(editor.caret.inputIndex);\n\t }\n\t }\n\t\n\t editor.toolbar.move();\n\t\n\t if (!editor.toolbar.opened) {\n\t\n\t editor.toolbar.open();\n\t }\n\t\n\t /** Updating inputs state */\n\t editor.ui.saveInputs();\n\t\n\t /** Prevent default browser behaviour */\n\t event.preventDefault();\n\t };\n\t\n\t /**\r\n\t * This method is used to observe pasted dirty data.\r\n\t *\r\n\t * Mutation handlers send to separate observers each mutation (added, changed and so on), which will be\r\n\t * passed from handler that sanitizes and replaces data.\r\n\t *\r\n\t * Probably won't be used\r\n\t *\r\n\t * @deprecated\r\n\t *\r\n\t * @param event\r\n\t * @private\r\n\t */\n\t callbacks._blockPasteCallback = function () {\n\t\n\t var currentInputIndex = editor.caret.getCurrentInputIndex();\n\t\n\t /**\r\n\t * create an observer instance\r\n\t */\n\t var observer = new MutationObserver(editor.callback.handleMutationsOnPaste);\n\t\n\t /**\r\n\t * configuration of the observer:\r\n\t */\n\t var config = {\n\t attributes: true,\n\t childList: false,\n\t characterData: false,\n\t subtree: true\n\t };\n\t\n\t // pass in the target node, as well as the observer options\n\t observer.observe(editor.state.inputs[currentInputIndex], config);\n\t };\n\t\n\t /**\r\n\t * This method prevents default behaviour.\r\n\t *\r\n\t * We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.\r\n\t * Firstly, we need to memorize the caret position. We can do that by getting the range of selection.\r\n\t * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node\r\n\t *\r\n\t * @param event\r\n\t */\n\t callbacks.blockPasteCallback = function (event) {\n\t\n\t /** Prevent default behaviour */\n\t event.preventDefault();\n\t\n\t var editableParent = editor.content.getEditableParent(event.target),\n\t firstLevelBlock = editor.content.getFirstLevelBlock(event.target);\n\t\n\t /** Allow paste when event target placed in Editable element */\n\t if (!editableParent) {\n\t\n\t return;\n\t }\n\t\n\t /** get html pasted data - dirty data */\n\t var data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain');\n\t\n\t /** Temporary DIV that is used to work with childs as arrays item */\n\t var div = editor.draw.node('DIV', '', {}),\n\t cleaner = new editor.sanitizer.init(editor.sanitizer.Config.BASIC),\n\t cleanData,\n\t fragment;\n\t\n\t /** Create fragment, that we paste to range after proccesing */\n\t fragment = document.createDocumentFragment();\n\t\n\t cleanData = cleaner.clean(data);\n\t\n\t div.innerHTML = cleanData;\n\t\n\t var node, lastNode;\n\t\n\t /**\r\n\t * and fill in fragment\r\n\t */\n\t while (node = div.firstChild) {\n\t\n\t lastNode = fragment.appendChild(node);\n\t }\n\t\n\t if (editor.tools[firstLevelBlock.dataset.tool].allowRenderOnPaste) {\n\t\n\t if (editor.paste.pasted(event)) return;\n\t }\n\t\n\t /**\r\n\t * work with selection and range\r\n\t */\n\t var selection, range;\n\t\n\t selection = window.getSelection();\n\t\n\t range = selection.getRangeAt(0);\n\t range.deleteContents();\n\t\n\t range.insertNode(fragment);\n\t\n\t /** Preserve the selection */\n\t if (lastNode) {\n\t\n\t range = range.cloneRange();\n\t range.setStartAfter(lastNode);\n\t range.collapse(true);\n\t selection.removeAllRanges();\n\t selection.addRange(range);\n\t }\n\t };\n\t\n\t /**\r\n\t * Sends all mutations to paste handler\r\n\t */\n\t callbacks.handleMutationsOnPaste = function (mutations) {\n\t\n\t var self = this;\n\t\n\t /**\r\n\t * Calling function with context of this function.\r\n\t * Also, we should sanitize pasted or changed data one time and ignore\r\n\t * changings which makes sanitize method.\r\n\t * For that, we need to send Context, MutationObserver.__proto__ that contains\r\n\t * observer disconnect method.\r\n\t */\n\t mutations.forEach(function (mutation) {\n\t\n\t editor.content.paste.call(self, mutation);\n\t });\n\t };\n\t\n\t /**\r\n\t * Clicks on block settings button\r\n\t */\n\t callbacks.showSettingsButtonClicked = function () {\n\t\n\t /**\r\n\t * Get type of current block\r\n\t * It uses to append settings from tool.settings property.\r\n\t * ...\r\n\t * Type is stored in data-type attribute on block\r\n\t */\n\t var currentToolType = editor.content.currentNode.dataset.tool;\n\t\n\t editor.toolbar.settings.toggle(currentToolType);\n\t\n\t /** Close toolbox when settings button is active */\n\t editor.toolbar.toolbox.close();\n\t editor.toolbar.settings.hideRemoveActions();\n\t };\n\t\n\t return callbacks;\n\t}({});\n\n/***/ },\n/* 13 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Draw module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0.\r\n\t */\n\t\n\tmodule.exports = function (draw) {\n\t\n\t /**\r\n\t * Base editor wrapper\r\n\t */\n\t draw.wrapper = function () {\n\t\n\t var wrapper = document.createElement('div');\n\t\n\t wrapper.className += 'codex-editor';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\r\n\t * Content-editable holder\r\n\t */\n\t draw.redactor = function () {\n\t\n\t var redactor = document.createElement('div');\n\t\n\t redactor.className += 'ce-redactor';\n\t\n\t return redactor;\n\t };\n\t\n\t draw.ceBlock = function () {\n\t\n\t var block = document.createElement('DIV');\n\t\n\t block.className += 'ce_block';\n\t\n\t return block;\n\t };\n\t\n\t /**\r\n\t * Empty toolbar with toggler\r\n\t */\n\t draw.toolbar = function () {\n\t\n\t var bar = document.createElement('div');\n\t\n\t bar.className += 'ce-toolbar';\n\t\n\t return bar;\n\t };\n\t\n\t draw.toolbarContent = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.classList.add('ce-toolbar__content');\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\r\n\t * Inline toolbar\r\n\t */\n\t draw.inlineToolbar = function () {\n\t\n\t var bar = document.createElement('DIV');\n\t\n\t bar.className += 'ce-toolbar-inline';\n\t\n\t return bar;\n\t };\n\t\n\t /**\r\n\t * Wrapper for inline toobar buttons\r\n\t */\n\t draw.inlineToolbarButtons = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.className += 'ce-toolbar-inline__buttons';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\r\n\t * For some actions\r\n\t */\n\t draw.inlineToolbarActions = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.className += 'ce-toolbar-inline__actions';\n\t\n\t return wrapper;\n\t };\n\t\n\t draw.inputForLink = function () {\n\t\n\t var input = document.createElement('INPUT');\n\t\n\t input.type = 'input';\n\t input.className += 'inputForLink';\n\t input.placeholder = 'Вставьте ссылку ...';\n\t input.setAttribute('form', 'defaultForm');\n\t\n\t input.setAttribute('autofocus', 'autofocus');\n\t\n\t return input;\n\t };\n\t\n\t /**\r\n\t * @todo Desc\r\n\t */\n\t draw.blockButtons = function () {\n\t\n\t var block = document.createElement('div');\n\t\n\t block.className += 'ce-toolbar__actions';\n\t\n\t return block;\n\t };\n\t\n\t /**\r\n\t * Block settings panel\r\n\t */\n\t draw.blockSettings = function () {\n\t\n\t var settings = document.createElement('div');\n\t\n\t settings.className += 'ce-settings';\n\t\n\t return settings;\n\t };\n\t\n\t draw.defaultSettings = function () {\n\t\n\t var div = document.createElement('div');\n\t\n\t div.classList.add('ce-settings_default');\n\t\n\t return div;\n\t };\n\t\n\t draw.pluginsSettings = function () {\n\t\n\t var div = document.createElement('div');\n\t\n\t div.classList.add('ce-settings_plugin');\n\t\n\t return div;\n\t };\n\t\n\t draw.plusButton = function () {\n\t\n\t var button = document.createElement('span');\n\t\n\t button.className = 'ce-toolbar__plus';\n\t // button.innerHTML = '<i class=\"ce-icon-plus\"></i>';\n\t\n\t return button;\n\t };\n\t\n\t /**\r\n\t * Settings button in toolbar\r\n\t */\n\t draw.settingsButton = function () {\n\t\n\t var toggler = document.createElement('span');\n\t\n\t toggler.className = 'ce-toolbar__settings-btn';\n\t\n\t /** Toggler button*/\n\t toggler.innerHTML = '<i class=\"ce-icon-cog\"></i>';\n\t\n\t return toggler;\n\t };\n\t\n\t /**\r\n\t * Redactor tools wrapper\r\n\t */\n\t\n\t draw.toolbox = function () {\n\t\n\t var wrapper = document.createElement('div');\n\t\n\t wrapper.className = 'ce-toolbar__tools';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\r\n\t * @protected\r\n\t *\r\n\t * Draws tool buttons for toolbox\r\n\t *\r\n\t * @param {String} type\r\n\t * @param {String} classname\r\n\t * @returns {Element}\r\n\t */\n\t draw.toolbarButton = function (type, classname) {\n\t\n\t var button = document.createElement('li'),\n\t toolIcon = document.createElement('i'),\n\t toolTitle = document.createElement('span');\n\t\n\t button.dataset.type = type;\n\t button.setAttribute('title', type);\n\t\n\t toolIcon.classList.add(classname);\n\t toolTitle.classList.add('ce_toolbar_tools--title');\n\t\n\t button.appendChild(toolIcon);\n\t button.appendChild(toolTitle);\n\t\n\t return button;\n\t };\n\t\n\t /**\r\n\t * @protected\r\n\t *\r\n\t * Draws tools for inline toolbar\r\n\t *\r\n\t * @param {String} type\r\n\t * @param {String} classname\r\n\t */\n\t draw.toolbarButtonInline = function (type, classname) {\n\t\n\t var button = document.createElement('BUTTON'),\n\t toolIcon = document.createElement('I');\n\t\n\t button.type = 'button';\n\t button.dataset.type = type;\n\t toolIcon.classList.add(classname);\n\t\n\t button.appendChild(toolIcon);\n\t\n\t return button;\n\t };\n\t\n\t /**\r\n\t * Redactor block\r\n\t */\n\t draw.block = function (tagName, content) {\n\t\n\t var node = document.createElement(tagName);\n\t\n\t node.innerHTML = content || '';\n\t\n\t return node;\n\t };\n\t\n\t /**\r\n\t * Creates Node with passed tagName and className\r\n\t * @param {string} tagName\r\n\t * @param {string} className\r\n\t * @param {object} properties - allow to assign properties\r\n\t */\n\t draw.node = function (tagName, className, properties) {\n\t\n\t var el = document.createElement(tagName);\n\t\n\t if (className) el.className = className;\n\t\n\t if (properties) {\n\t\n\t for (var name in properties) {\n\t\n\t el[name] = properties[name];\n\t }\n\t }\n\t\n\t return el;\n\t };\n\t\n\t /**\r\n\t * Unavailable plugin block\r\n\t */\n\t draw.unavailableBlock = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.classList.add('cdx-unavailable-block');\n\t\n\t return wrapper;\n\t };\n\t\n\t return draw;\n\t}({});\n\n/***/ },\n/* 14 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Caret Module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (caret) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\r\n\t * @var {int} InputIndex - editable element in DOM\r\n\t */\n\t caret.inputIndex = null;\n\t\n\t /**\r\n\t * @var {int} offset - caret position in a text node.\r\n\t */\n\t caret.offset = null;\n\t\n\t /**\r\n\t * @var {int} focusedNodeIndex - we get index of child node from first-level block\r\n\t */\n\t caret.focusedNodeIndex = null;\n\t\n\t /**\r\n\t * Creates Document Range and sets caret to the element.\r\n\t * @protected\r\n\t * @uses caret.save — if you need to save caret position\r\n\t * @param {Element} el - Changed Node.\r\n\t */\n\t caret.set = function (el, index, offset) {\n\t\n\t offset = offset || caret.offset || 0;\n\t index = index || caret.focusedNodeIndex || 0;\n\t\n\t var childs = el.childNodes,\n\t nodeToSet;\n\t\n\t if (childs.length === 0) {\n\t\n\t nodeToSet = el;\n\t } else {\n\t\n\t nodeToSet = childs[index];\n\t }\n\t\n\t /** If Element is INPUT */\n\t if (el.tagName == 'INPUT') {\n\t\n\t el.focus();\n\t return;\n\t }\n\t\n\t if (editor.core.isDomNode(nodeToSet)) {\n\t\n\t nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);\n\t }\n\t\n\t var range = document.createRange(),\n\t selection = window.getSelection();\n\t\n\t window.setTimeout(function () {\n\t\n\t range.setStart(nodeToSet, offset);\n\t range.setEnd(nodeToSet, offset);\n\t\n\t selection.removeAllRanges();\n\t selection.addRange(range);\n\t\n\t editor.caret.saveCurrentInputIndex();\n\t }, 20);\n\t };\n\t\n\t /**\r\n\t * @protected\r\n\t * Updates index of input and saves it in caret object\r\n\t */\n\t caret.saveCurrentInputIndex = function () {\n\t\n\t /** Index of Input that we paste sanitized content */\n\t var selection = window.getSelection(),\n\t inputs = editor.state.inputs,\n\t focusedNode = selection.anchorNode,\n\t focusedNodeHolder;\n\t\n\t if (!focusedNode) {\n\t\n\t return;\n\t }\n\t\n\t /** Looking for parent contentEditable block */\n\t while (focusedNode.contentEditable != 'true') {\n\t\n\t focusedNodeHolder = focusedNode.parentNode;\n\t focusedNode = focusedNodeHolder;\n\t }\n\t\n\t /** Input index in DOM level */\n\t var editableElementIndex = 0;\n\t\n\t while (focusedNode != inputs[editableElementIndex]) {\n\t\n\t editableElementIndex++;\n\t }\n\t\n\t caret.inputIndex = editableElementIndex;\n\t };\n\t\n\t /**\r\n\t * Returns current input index (caret object)\r\n\t */\n\t caret.getCurrentInputIndex = function () {\n\t\n\t return caret.inputIndex;\n\t };\n\t\n\t /**\r\n\t * @param {int} index - index of first-level block after that we set caret into next input\r\n\t */\n\t caret.setToNextBlock = function (index) {\n\t\n\t var inputs = editor.state.inputs,\n\t nextInput = inputs[index + 1];\n\t\n\t if (!nextInput) {\n\t\n\t editor.core.log('We are reached the end');\n\t return;\n\t }\n\t\n\t /**\r\n\t * When new Block created or deleted content of input\r\n\t * We should add some text node to set caret\r\n\t */\n\t if (!nextInput.childNodes.length) {\n\t\n\t var emptyTextElement = document.createTextNode('');\n\t\n\t nextInput.appendChild(emptyTextElement);\n\t }\n\t\n\t editor.caret.inputIndex = index + 1;\n\t editor.caret.set(nextInput, 0, 0);\n\t editor.content.workingNodeChanged(nextInput);\n\t };\n\t\n\t /**\r\n\t * @param {int} index - index of target input.\r\n\t * Sets caret to input with this index\r\n\t */\n\t caret.setToBlock = function (index) {\n\t\n\t var inputs = editor.state.inputs,\n\t targetInput = inputs[index];\n\t\n\t if (!targetInput) {\n\t\n\t return;\n\t }\n\t\n\t /**\r\n\t * When new Block created or deleted content of input\r\n\t * We should add some text node to set caret\r\n\t */\n\t if (!targetInput.childNodes.length) {\n\t\n\t var emptyTextElement = document.createTextNode('');\n\t\n\t targetInput.appendChild(emptyTextElement);\n\t }\n\t\n\t editor.caret.inputIndex = index;\n\t editor.caret.set(targetInput, 0, 0);\n\t editor.content.workingNodeChanged(targetInput);\n\t };\n\t\n\t /**\r\n\t * @param {int} index - index of input\r\n\t */\n\t caret.setToPreviousBlock = function (index) {\n\t\n\t index = index || 0;\n\t\n\t var inputs = editor.state.inputs,\n\t previousInput = inputs[index - 1],\n\t lastChildNode,\n\t lengthOfLastChildNode,\n\t emptyTextElement;\n\t\n\t if (!previousInput) {\n\t\n\t editor.core.log('We are reached first node');\n\t return;\n\t }\n\t\n\t lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length);\n\t lengthOfLastChildNode = lastChildNode.length;\n\t\n\t /**\r\n\t * When new Block created or deleted content of input\r\n\t * We should add some text node to set caret\r\n\t */\n\t if (!previousInput.childNodes.length) {\n\t\n\t emptyTextElement = document.createTextNode('');\n\t previousInput.appendChild(emptyTextElement);\n\t }\n\t editor.caret.inputIndex = index - 1;\n\t editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode);\n\t editor.content.workingNodeChanged(inputs[index - 1]);\n\t };\n\t\n\t caret.position = {\n\t\n\t atStart: function atStart() {\n\t\n\t var selection = window.getSelection(),\n\t anchorOffset = selection.anchorOffset,\n\t anchorNode = selection.anchorNode,\n\t firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode),\n\t pluginsRender = firstLevelBlock.childNodes[0];\n\t\n\t if (!editor.core.isDomNode(anchorNode)) {\n\t\n\t anchorNode = anchorNode.parentNode;\n\t }\n\t\n\t var isFirstNode = anchorNode === pluginsRender.childNodes[0],\n\t isOffsetZero = anchorOffset === 0;\n\t\n\t return isFirstNode && isOffsetZero;\n\t },\n\t\n\t atTheEnd: function atTheEnd() {\n\t\n\t var selection = window.getSelection(),\n\t anchorOffset = selection.anchorOffset,\n\t anchorNode = selection.anchorNode;\n\t\n\t /** Caret is at the end of input */\n\t return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length;\n\t }\n\t };\n\t\n\t return caret;\n\t}({});\n\n/***/ },\n/* 15 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Notification Module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (notifications) {\n\t\n\t var editor = codex.editor;\n\t\n\t var queue = [];\n\t\n\t var addToQueue = function addToQueue(settings) {\n\t\n\t queue.push(settings);\n\t\n\t var index = 0;\n\t\n\t while (index < queue.length && queue.length > 5) {\n\t\n\t if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n\t\n\t index++;\n\t continue;\n\t }\n\t\n\t queue[index].close();\n\t queue.splice(index, 1);\n\t }\n\t };\n\t\n\t notifications.createHolder = function () {\n\t\n\t var holder = editor.draw.node('DIV', 'cdx-notifications-block');\n\t\n\t editor.nodes.notifications = document.body.appendChild(holder);\n\t\n\t return holder;\n\t };\n\t\n\t /**\r\n\t * Error notificator. Shows block with message\r\n\t * @protected\r\n\t */\n\t notifications.errorThrown = function (errorMsg, event) {\n\t\n\t editor.notifications.notification({ message: 'This action is not available currently', type: event.type });\n\t };\n\t\n\t /**\r\n\t *\r\n\t * Appends notification\r\n\t *\r\n\t * settings = {\r\n\t * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\r\n\t * message - notification message\r\n\t * okMsg - confirm button text (default - 'Ok')\r\n\t * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\r\n\t * confirm - function-handler for ok button click\r\n\t * cancel - function-handler for cancel button click. Only for confirm and prompt types\r\n\t * time - time (in seconds) after which notification will close (default - 10s)\r\n\t * }\r\n\t *\r\n\t * @param settings\r\n\t */\n\t notifications.notification = function (constructorSettings) {\n\t\n\t /** Private vars and methods */\n\t var notification = null,\n\t cancel = null,\n\t type = null,\n\t confirm = null,\n\t inputField = null;\n\t\n\t var confirmHandler = function confirmHandler() {\n\t\n\t close();\n\t\n\t if (typeof confirm !== 'function') {\n\t\n\t return;\n\t }\n\t\n\t if (type == 'prompt') {\n\t\n\t confirm(inputField.value);\n\t return;\n\t }\n\t\n\t confirm();\n\t };\n\t\n\t var cancelHandler = function cancelHandler() {\n\t\n\t close();\n\t\n\t if (typeof cancel !== 'function') {\n\t\n\t return;\n\t }\n\t\n\t cancel();\n\t };\n\t\n\t /** Public methods */\n\t function create(settings) {\n\t\n\t if (!(settings && settings.message)) {\n\t\n\t editor.core.log('Can\\'t create notification. Message is missed');\n\t return;\n\t }\n\t\n\t settings.type = settings.type || 'alert';\n\t settings.time = settings.time * 1000 || 10000;\n\t\n\t var wrapper = editor.draw.node('DIV', 'cdx-notification'),\n\t message = editor.draw.node('DIV', 'cdx-notification__message'),\n\t input = editor.draw.node('INPUT', 'cdx-notification__input'),\n\t okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\n\t cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\n\t\n\t message.textContent = settings.message;\n\t okBtn.textContent = settings.okMsg || 'ОК';\n\t cancelBtn.textContent = settings.cancelMsg || 'Отмена';\n\t\n\t editor.listeners.add(okBtn, 'click', confirmHandler);\n\t editor.listeners.add(cancelBtn, 'click', cancelHandler);\n\t\n\t wrapper.appendChild(message);\n\t\n\t if (settings.type == 'prompt') {\n\t\n\t wrapper.appendChild(input);\n\t }\n\t\n\t wrapper.appendChild(okBtn);\n\t\n\t if (settings.type == 'prompt' || settings.type == 'confirm') {\n\t\n\t wrapper.appendChild(cancelBtn);\n\t }\n\t\n\t wrapper.classList.add('cdx-notification-' + settings.type);\n\t wrapper.dataset.type = settings.type;\n\t\n\t notification = wrapper;\n\t type = settings.type;\n\t confirm = settings.confirm;\n\t cancel = settings.cancel;\n\t inputField = input;\n\t\n\t if (settings.type != 'prompt' && settings.type != 'confirm') {\n\t\n\t window.setTimeout(close, settings.time);\n\t }\n\t };\n\t\n\t function send() {\n\t\n\t editor.nodes.notifications.appendChild(notification);\n\t inputField.focus();\n\t\n\t editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\n\t\n\t window.setTimeout(function () {\n\t\n\t editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n\t }, 100);\n\t\n\t addToQueue({ type: type, close: close });\n\t };\n\t\n\t function close() {\n\t\n\t notification.remove();\n\t };\n\t\n\t if (constructorSettings) {\n\t\n\t create(constructorSettings);\n\t send();\n\t }\n\t\n\t return {\n\t create: create,\n\t send: send,\n\t close: close\n\t };\n\t };\n\t\n\t notifications.clear = function () {\n\t\n\t editor.nodes.notifications.innerHTML = '';\n\t queue = [];\n\t };\n\t\n\t return notifications;\n\t}({});\n\n/***/ },\n/* 16 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\t/**\r\n\t * Codex Editor Parser Module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.1\r\n\t */\n\t\n\tmodule.exports = function (parser) {\n\t\n\t var editor = codex.editor;\n\t\n\t /** inserting text */\n\t parser.insertPastedContent = function (blockType, tag) {\n\t\n\t editor.content.insertBlock({\n\t type: blockType.type,\n\t block: blockType.render({\n\t text: tag.innerHTML\n\t })\n\t });\n\t };\n\t\n\t /**\r\n\t * Check DOM node for display style: separated block or child-view\r\n\t */\n\t parser.isFirstLevelBlock = function (node) {\n\t\n\t return node.nodeType == editor.core.nodeTypes.TAG && node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n\t };\n\t\n\t return parser;\n\t}({});\n\n/***/ },\n/* 17 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Sanitizer\r\n\t */\n\t\n\tmodule.exports = function (sanitizer) {\n\t\n\t var janitor = __webpack_require__(18);\n\t\n\t /**\r\n\t * Basic config\r\n\t */\n\t var Config = {\n\t\n\t BASIC: {\n\t\n\t tags: {\n\t p: {},\n\t a: {\n\t href: true,\n\t target: '_blank',\n\t rel: 'nofollow'\n\t },\n\t i: {},\n\t b: {},\n\t strong: {},\n\t em: {},\n\t span: {}\n\t }\n\t }\n\t };\n\t\n\t sanitizer.Config = Config;\n\t\n\t sanitizer.init = janitor;\n\t\n\t return sanitizer;\n\t}({});\n\n/***/ },\n/* 18 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory) {\n\t if (true) {\n\t !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t } else if (typeof exports === 'object') {\n\t module.exports = factory();\n\t } else {\n\t root.HTMLJanitor = factory();\n\t }\n\t}(this, function () {\n\t\n\t /**\n\t * @param {Object} config.tags Dictionary of allowed tags.\n\t * @param {boolean} config.keepNestedBlockElements Default false.\n\t */\n\t function HTMLJanitor(config) {\n\t\n\t var tagDefinitions = config['tags'];\n\t var tags = Object.keys(tagDefinitions);\n\t\n\t var validConfigValues = tags\n\t .map(function(k) { return typeof tagDefinitions[k]; })\n\t .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; });\n\t\n\t if(!validConfigValues) {\n\t throw new Error(\"The configuration was invalid\");\n\t }\n\t\n\t this.config = config;\n\t }\n\t\n\t // TODO: not exhaustive?\n\t var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE'];\n\t function isBlockElement(node) {\n\t return blockElementNames.indexOf(node.nodeName) !== -1;\n\t }\n\t\n\t var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE'];\n\t function isInlineElement(node) {\n\t return inlineElementNames.indexOf(node.nodeName) !== -1;\n\t }\n\t\n\t HTMLJanitor.prototype.clean = function (html) {\n\t var sandbox = document.createElement('div');\n\t sandbox.innerHTML = html;\n\t\n\t this._sanitize(sandbox);\n\t\n\t return sandbox.innerHTML;\n\t };\n\t\n\t HTMLJanitor.prototype._sanitize = function (parentNode) {\n\t var treeWalker = createTreeWalker(parentNode);\n\t var node = treeWalker.firstChild();\n\t if (!node) { return; }\n\t\n\t do {\n\t // Ignore nodes that have already been sanitized\n\t if (node._sanitized) {\n\t continue;\n\t }\n\t\n\t if (node.nodeType === Node.TEXT_NODE) {\n\t // If this text node is just whitespace and the previous or next element\n\t // sibling is a block element, remove it\n\t // N.B.: This heuristic could change. Very specific to a bug with\n\t // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output\n\t // FIXME: make this an option?\n\t if (node.data.trim() === ''\n\t && ((node.previousElementSibling && isBlockElement(node.previousElementSibling))\n\t || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) {\n\t parentNode.removeChild(node);\n\t this._sanitize(parentNode);\n\t break;\n\t } else {\n\t continue;\n\t }\n\t }\n\t\n\t // Remove all comments\n\t if (node.nodeType === Node.COMMENT_NODE) {\n\t parentNode.removeChild(node);\n\t this._sanitize(parentNode);\n\t break;\n\t }\n\t\n\t var isInline = isInlineElement(node);\n\t var containsBlockElement;\n\t if (isInline) {\n\t containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement);\n\t }\n\t\n\t // Block elements should not be nested (e.g. <li><p>...); if\n\t // they are, we want to unwrap the inner block element.\n\t var isNotTopContainer = !! parentNode.parentNode;\n\t var isNestedBlockElement =\n\t isBlockElement(parentNode) &&\n\t isBlockElement(node) &&\n\t isNotTopContainer;\n\t\n\t var nodeName = node.nodeName.toLowerCase();\n\t\n\t var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\t\n\t var isInvalid = isInline && containsBlockElement;\n\t\n\t // Drop tag entirely according to the whitelist *and* if the markup\n\t // is invalid.\n\t if (isInvalid || shouldRejectNode(node, allowedAttrs)\n\t || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n\t // Do not keep the inner text of SCRIPT/STYLE elements.\n\t if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n\t while (node.childNodes.length > 0) {\n\t parentNode.insertBefore(node.childNodes[0], node);\n\t }\n\t }\n\t parentNode.removeChild(node);\n\t\n\t this._sanitize(parentNode);\n\t break;\n\t }\n\t\n\t // Sanitize attributes\n\t for (var a = 0; a < node.attributes.length; a += 1) {\n\t var attr = node.attributes[a];\n\t\n\t if (shouldRejectAttr(attr, allowedAttrs, node)) {\n\t node.removeAttribute(attr.name);\n\t // Shift the array to continue looping.\n\t a = a - 1;\n\t }\n\t }\n\t\n\t // Sanitize children\n\t this._sanitize(node);\n\t\n\t // Mark node as sanitized so it's ignored in future runs\n\t node._sanitized = true;\n\t } while ((node = treeWalker.nextSibling()));\n\t };\n\t\n\t function createTreeWalker(node) {\n\t return document.createTreeWalker(node,\n\t NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n\t null, false);\n\t }\n\t\n\t function getAllowedAttrs(config, nodeName, node){\n\t if (typeof config.tags[nodeName] === 'function') {\n\t return config.tags[nodeName](node);\n\t } else {\n\t return config.tags[nodeName];\n\t }\n\t }\n\t\n\t function shouldRejectNode(node, allowedAttrs){\n\t if (typeof allowedAttrs === 'undefined') {\n\t return true;\n\t } else if (typeof allowedAttrs === 'boolean') {\n\t return !allowedAttrs;\n\t }\n\t\n\t return false;\n\t }\n\t\n\t function shouldRejectAttr(attr, allowedAttrs, node){\n\t var attrName = attr.name.toLowerCase();\n\t\n\t if (allowedAttrs === true){\n\t return false;\n\t } else if (typeof allowedAttrs[attrName] === 'function'){\n\t return !allowedAttrs[attrName](attr.value, node);\n\t } else if (typeof allowedAttrs[attrName] === 'undefined'){\n\t return true;\n\t } else if (allowedAttrs[attrName] === false) {\n\t return true;\n\t } else if (typeof allowedAttrs[attrName] === 'string') {\n\t return (allowedAttrs[attrName] !== attr.value);\n\t }\n\t\n\t return false;\n\t }\n\t\n\t return HTMLJanitor;\n\t\n\t}));\n\n\n/***/ },\n/* 19 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Anchors module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (anchors) {\n\t\n\t var editor = codex.editor;\n\t\n\t anchors.input = null;\n\t anchors.currentNode = null;\n\t\n\t anchors.settingsOpened = function (currentBlock) {\n\t\n\t anchors.currentNode = currentBlock;\n\t anchors.input.value = anchors.currentNode.dataset.anchor || '';\n\t };\n\t\n\t anchors.anchorChanged = function (e) {\n\t\n\t var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);\n\t\n\t anchors.currentNode.dataset.anchor = newAnchor;\n\t\n\t if (newAnchor.trim() !== '') {\n\t\n\t anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t } else {\n\t\n\t anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t };\n\t\n\t anchors.keyDownOnAnchorInput = function (e) {\n\t\n\t if (e.keyCode == editor.core.keys.ENTER) {\n\t\n\t e.preventDefault();\n\t e.stopPropagation();\n\t\n\t e.target.blur();\n\t editor.toolbar.settings.close();\n\t }\n\t };\n\t\n\t anchors.keyUpOnAnchorInput = function (e) {\n\t\n\t if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {\n\t\n\t e.stopPropagation();\n\t }\n\t };\n\t\n\t anchors.rusToTranslit = function (string) {\n\t\n\t var ru = ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'],\n\t 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'];\n\t\n\t for (var i = 0; i < ru.length; i++) {\n\t\n\t string = string.split(ru[i]).join(en[i]);\n\t string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());\n\t }\n\t\n\t string = string.replace(/[^0-9a-zA-Z_]+/g, '-');\n\t\n\t return string;\n\t };\n\t\n\t return anchors;\n\t}({});\n\n/***/ },\n/* 20 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\t/**\r\n\t * Codex Editor Listeners module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\t/**\r\n\t * Module-decorator for event listeners assignment\r\n\t */\n\tmodule.exports = function (listeners) {\n\t\n\t var allListeners = [];\n\t\n\t /**\r\n\t * Search methods\r\n\t *\r\n\t * byElement, byType and byHandler returns array of suitable listeners\r\n\t * one and all takes element, eventType, and handler and returns first (all) suitable listener\r\n\t *\r\n\t */\n\t listeners.search = function () {\n\t\n\t var byElement = function byElement(element, context) {\n\t\n\t var listenersOnElement = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.element === element) {\n\t\n\t listenersOnElement.push(listener);\n\t }\n\t }\n\t\n\t return listenersOnElement;\n\t };\n\t\n\t var byType = function byType(eventType, context) {\n\t\n\t var listenersWithType = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.type === eventType) {\n\t\n\t listenersWithType.push(listener);\n\t }\n\t }\n\t\n\t return listenersWithType;\n\t };\n\t\n\t var byHandler = function byHandler(handler, context) {\n\t\n\t var listenersWithHandler = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.handler === handler) {\n\t\n\t listenersWithHandler.push(listener);\n\t }\n\t }\n\t\n\t return listenersWithHandler;\n\t };\n\t\n\t var one = function one(element, eventType, handler) {\n\t\n\t var result = allListeners;\n\t\n\t if (element) result = byElement(element, result);\n\t\n\t if (eventType) result = byType(eventType, result);\n\t\n\t if (handler) result = byHandler(handler, result);\n\t\n\t return result[0];\n\t };\n\t\n\t var all = function all(element, eventType, handler) {\n\t\n\t var result = allListeners;\n\t\n\t if (element) result = byElement(element, result);\n\t\n\t if (eventType) result = byType(eventType, result);\n\t\n\t if (handler) result = byHandler(handler, result);\n\t\n\t return result;\n\t };\n\t\n\t return {\n\t byElement: byElement,\n\t byType: byType,\n\t byHandler: byHandler,\n\t one: one,\n\t all: all\n\t };\n\t }();\n\t\n\t listeners.add = function (element, eventType, handler, isCapture) {\n\t\n\t element.addEventListener(eventType, handler, isCapture);\n\t\n\t var data = {\n\t element: element,\n\t type: eventType,\n\t handler: handler\n\t };\n\t\n\t var alreadyAddedListener = listeners.search.one(element, eventType, handler);\n\t\n\t if (!alreadyAddedListener) {\n\t\n\t allListeners.push(data);\n\t }\n\t };\n\t\n\t listeners.remove = function (element, eventType, handler) {\n\t\n\t element.removeEventListener(eventType, handler);\n\t\n\t var existingListeners = listeners.search.all(element, eventType, handler);\n\t\n\t for (var i = 0; i < existingListeners.length; i++) {\n\t\n\t var index = allListeners.indexOf(existingListeners[i]);\n\t\n\t if (index > 0) {\n\t\n\t allListeners.splice(index, 1);\n\t }\n\t }\n\t };\n\t\n\t listeners.removeAll = function () {\n\t\n\t allListeners.map(function (current) {\n\t\n\t listeners.remove(current.element, current.type, current.handler);\n\t });\n\t };\n\t\n\t listeners.get = function (element, eventType, handler) {\n\t\n\t return listeners.search.all(element, eventType, handler);\n\t };\n\t\n\t return listeners;\n\t}({});\n\n/***/ },\n/* 21 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tvar _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; };\n\t\n\t/**\r\n\t * Codex Editor Destroyer module\r\n\t *\r\n\t * @auhor Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (destroyer) {\n\t\n\t var editor = codex.editor;\n\t\n\t destroyer.removeNodes = function () {\n\t\n\t editor.nodes.wrapper.remove();\n\t editor.nodes.notifications.remove();\n\t };\n\t\n\t destroyer.destroyPlugins = function () {\n\t\n\t for (var tool in editor.tools) {\n\t\n\t if (typeof editor.tools[tool].destroy === 'function') {\n\t\n\t editor.tools[tool].destroy();\n\t }\n\t }\n\t };\n\t\n\t destroyer.destroyScripts = function () {\n\t\n\t var scripts = document.getElementsByTagName('SCRIPT');\n\t\n\t for (var i = 0; i < scripts.length; i++) {\n\t\n\t if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n\t\n\t scripts[i].remove();\n\t i--;\n\t }\n\t }\n\t };\n\t\n\t /**\r\n\t * Delete editor data from webpage.\r\n\t * You should send settings argument with boolean flags:\r\n\t * @param settings.ui- remove redactor event listeners and DOM nodes\r\n\t * @param settings.scripts - remove redactor scripts from DOM\r\n\t * @param settings.plugins - remove plugin's objects\r\n\t * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\r\n\t * }\r\n\t *\r\n\t */\n\t destroyer.destroy = function (settings) {\n\t\n\t if (!settings || (typeof settings === 'undefined' ? 'undefined' : _typeof(settings)) !== 'object') {\n\t\n\t return;\n\t }\n\t\n\t if (settings.ui) {\n\t\n\t destroyer.removeNodes();\n\t editor.listeners.removeAll();\n\t }\n\t\n\t if (settings.scripts) {\n\t\n\t destroyer.destroyScripts();\n\t }\n\t\n\t if (settings.plugins) {\n\t\n\t destroyer.destroyPlugins();\n\t }\n\t\n\t if (settings.ui && settings.scripts && settings.core) {\n\t\n\t delete codex.editor;\n\t }\n\t };\n\t\n\t return destroyer;\n\t}({});\n\n/***/ },\n/* 22 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\r\n\t * Codex Editor Paste module\r\n\t *\r\n\t * @author Codex Team\r\n\t * @version 1.0\r\n\t */\n\t\n\tmodule.exports = function (paste) {\n\t\n\t var editor = codex.editor;\n\t\n\t var patterns = [];\n\t\n\t paste.prepare = function () {\n\t\n\t var tools = editor.tools;\n\t\n\t for (var tool in tools) {\n\t\n\t if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n\t\n\t continue;\n\t }\n\t\n\t tools[tool].renderOnPastePatterns.map(function (pattern) {\n\t\n\t patterns.push(pattern);\n\t });\n\t }\n\t\n\t return Promise.resolve();\n\t };\n\t\n\t /**\r\n\t * Saves data\r\n\t * @param event\r\n\t */\n\t paste.pasted = function (event) {\n\t\n\t var clipBoardData = event.clipboardData || window.clipboardData,\n\t content = clipBoardData.getData('Text');\n\t\n\t var result = analize(content);\n\t\n\t if (result) {\n\t\n\t event.preventDefault();\n\t event.stopImmediatePropagation();\n\t }\n\t\n\t return result;\n\t };\n\t\n\t /**\r\n\t * Analizes pated string and calls necessary method\r\n\t */\n\t\n\t var analize = function analize(string) {\n\t\n\t var result = false,\n\t content = editor.content.currentNode,\n\t plugin = content.dataset.tool;\n\t\n\t patterns.map(function (pattern) {\n\t\n\t var execArray = pattern.regex.exec(string),\n\t match = execArray && execArray[0];\n\t\n\t if (match && match === string.trim()) {\n\t\n\t /** current block is not empty */\n\t if (content.textContent.trim() && plugin == editor.settings.initialBlockPlugin) {\n\t\n\t pasteToNewBlock_();\n\t }\n\t\n\t pattern.callback(string, pattern);\n\t result = true;\n\t }\n\t });\n\t\n\t return result;\n\t };\n\t\n\t var pasteToNewBlock_ = function pasteToNewBlock_() {\n\t\n\t /** Create new initial block */\n\t editor.content.insertBlock({\n\t\n\t type: editor.settings.initialBlockPlugin,\n\t block: editor.tools[editor.settings.initialBlockPlugin].render({\n\t text: ''\n\t })\n\t\n\t }, false);\n\t };\n\t\n\t return paste;\n\t}({});\n\n/***/ }\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// codex-editor.js"," \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\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\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.loaded = 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// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 5aa79d46a4d94eef2e64","/**\r\n *\r\n * Codex Editor\r\n *\r\n * @author Codex Team\r\n */\r\n\r\nmodule.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.anchors = require('./modules/anchors');\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 *\r\n * holds initial settings\r\n */\r\n editor.settings = {\r\n tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\r\n textareaId: 'codex-editor',\r\n uploadImagesUrl: '/editor/transport/',\r\n\r\n // Type of block showing on empty editor\r\n initialBlockPlugin: 'paragraph'\r\n };\r\n\r\n /**\r\n * public\r\n *\r\n * Static nodes\r\n */\r\n editor.nodes = {\r\n textarea : 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 /**\r\n * Initialization\r\n * @uses Promise cEditor.core.prepare\r\n * @param {} userSettings are :\r\n * - tools [],\r\n * - textareaId String\r\n * ...\r\n *\r\n * Load user defined tools\r\n * Tools must contain this important objects :\r\n * @param {String} type - this is a type of plugin. It can be used as plugin name\r\n * @param {String} iconClassname - this a icon in toolbar\r\n * @param {Object} make - what should plugin do, when it is clicked\r\n * @param {Object} appendCallback - callback after clicking\r\n * @param {Element} settings - what settings does it have\r\n * @param {Object} render - plugin get JSON, and should return HTML\r\n * @param {Object} save - plugin gets HTML content, returns JSON\r\n * @param {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\r\n * @param {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\r\n *\r\n * @example\r\n * - type : 'header',\r\n * - iconClassname : 'ce-icon-header',\r\n * - make : headerTool.make,\r\n * - appendCallback : headerTool.appendCallback,\r\n * - settings : headerTool.makeSettings(),\r\n * - render : headerTool.render,\r\n * - save : headerTool.save,\r\n * - displayInToolbox : true,\r\n * - enableLineBreaks : false\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.make)\r\n .then(editor.ui.addTools)\r\n .then(editor.ui.bindEvents)\r\n .then(editor.tools.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})({});\n\n\n// WEBPACK FOOTER //\n// ./codex.js","/**\r\n * Codex Editor Core\r\n *\r\n * @author Codex Team\r\n * @version 1.1.2\r\n */\r\n\r\nmodule.exports = (function (core) {\r\n\r\n let editor = codex.editor;\r\n\r\n /**\r\n * @public\r\n *\r\n * Editor preparing method\r\n * @return Promise\r\n */\r\n core.prepare = function (userSettings) {\r\n\r\n return new Promise(function (resolve, reject) {\r\n\r\n if ( userSettings ) {\r\n\r\n editor.settings.tools = userSettings.tools || editor.settings.tools;\r\n\r\n }\r\n\r\n if (userSettings.data) {\r\n\r\n editor.state.blocks = userSettings.data;\r\n\r\n }\r\n\r\n if (userSettings.initialBlockPlugin) {\r\n\r\n editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\r\n\r\n }\r\n\r\n if (userSettings.uploadImagesUrl) {\r\n\r\n editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;\r\n\r\n }\r\n\r\n editor.hideToolbar = userSettings.hideToolbar;\r\n\r\n editor.nodes.textarea = document.getElementById(userSettings.textareaId || editor.settings.textareaId);\r\n\r\n if (typeof editor.nodes.textarea === undefined || editor.nodes.textarea === null) {\r\n\r\n reject(Error(\"Textarea wasn't found by ID: #\" + userSettings.textareaId));\r\n\r\n } else {\r\n\r\n resolve();\r\n\r\n }\r\n\r\n });\r\n\r\n };\r\n\r\n /**\r\n * Logging method\r\n * @param type = ['log', 'info', 'warn']\r\n */\r\n core.log = function (msg, type, arg) {\r\n\r\n type = type || 'log';\r\n\r\n if (!arg) {\r\n\r\n arg = msg || 'undefined';\r\n msg = '[codex-editor]: %o';\r\n\r\n } else {\r\n\r\n msg = '[codex-editor]: ' + msg;\r\n\r\n }\r\n\r\n try{\r\n\r\n if ( 'console' in window && window.console[ type ] ) {\r\n\r\n if ( arg ) window.console[ type ]( msg, arg );\r\n else window.console[ type ]( msg );\r\n\r\n }\r\n\r\n }catch(e) {}\r\n\r\n };\r\n\r\n /**\r\n * @protected\r\n *\r\n * Helper for insert one element after another\r\n */\r\n core.insertAfter = function (target, element) {\r\n\r\n target.parentNode.insertBefore(element, target.nextSibling);\r\n\r\n };\r\n\r\n /**\r\n * @const\r\n *\r\n * Readable DOM-node types map\r\n */\r\n core.nodeTypes = {\r\n TAG : 1,\r\n TEXT : 3,\r\n COMMENT : 8\r\n };\r\n\r\n /**\r\n * @const\r\n * Readable keys map\r\n */\r\n core.keys = { BACKSPACE: 8, TAB: 9, ENTER: 13, SHIFT: 16, CTRL: 17, ALT: 18, ESC: 27, SPACE: 32, LEFT: 37, UP: 38, DOWN: 40, RIGHT: 39, DELETE: 46, META: 91 };\r\n\r\n /**\r\n * @protected\r\n *\r\n * Check object for DOM node\r\n */\r\n core.isDomNode = function (el) {\r\n\r\n return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG;\r\n\r\n };\r\n\r\n /**\r\n * Checks passed object for emptiness\r\n * @require ES5 - Object.keys\r\n * @param {object}\r\n */\r\n core.isEmpty = function ( obj ) {\r\n\r\n return Object.keys(obj).length === 0;\r\n\r\n };\r\n\r\n /**\r\n * Native Ajax\r\n */\r\n core.ajax = function (data) {\r\n\r\n if (!data || !data.url) {\r\n\r\n return;\r\n\r\n }\r\n\r\n var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\r\n successFunction = function () {},\r\n params = '',\r\n obj;\r\n\r\n data.async = true;\r\n data.type = data.type || 'GET';\r\n data.data = data.data || '';\r\n data['content-type'] = data['content-type'] || 'application/json; charset=utf-8';\r\n successFunction = data.success || successFunction ;\r\n\r\n if (data.type == 'GET' && data.data) {\r\n\r\n data.url = /\\?/.test(data.url) ? data.url + '&' + data.data : data.url + '?' + data.data;\r\n\r\n } else {\r\n\r\n for(obj in data.data) {\r\n\r\n params += (obj + '=' + encodeURIComponent(data.data[obj]) + '&');\r\n\r\n }\r\n\r\n }\r\n\r\n if (data.withCredentials) {\r\n\r\n XMLHTTP.withCredentials = true;\r\n\r\n }\r\n\r\n if (data.beforeSend && typeof data.beforeSend == 'function') {\r\n\r\n data.beforeSend.call();\r\n\r\n }\r\n\r\n XMLHTTP.open( data.type, data.url, data.async );\r\n XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\r\n XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\r\n\r\n XMLHTTP.onreadystatechange = function () {\r\n\r\n if (XMLHTTP.readyState == 4 && XMLHTTP.status == 200) {\r\n\r\n successFunction(XMLHTTP.responseText);\r\n\r\n }\r\n\r\n };\r\n\r\n XMLHTTP.send(params);\r\n\r\n };\r\n\r\n /**\r\n * Appends script to head of document\r\n * @return Promise\r\n */\r\n core.importScript = function (scriptPath, instanceName) {\r\n\r\n return new Promise(function (resolve, reject) {\r\n\r\n let script;\r\n\r\n /** Script is already loaded */\r\n if ( !instanceName ) {\r\n\r\n reject('Instance name is missed');\r\n\r\n } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) {\r\n\r\n resolve(scriptPath);\r\n\r\n }\r\n\r\n script = document.createElement('SCRIPT');\r\n script.async = true;\r\n script.defer = true;\r\n script.id = editor.scriptPrefix + instanceName;\r\n\r\n script.onload = function () {\r\n\r\n resolve(scriptPath);\r\n\r\n };\r\n\r\n script.onerror = function () {\r\n\r\n reject(scriptPath);\r\n\r\n };\r\n\r\n script.src = scriptPath;\r\n document.head.appendChild(script);\r\n\r\n });\r\n\r\n };\r\n\r\n return core;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/core.js","/**\r\n* Module working with plugins\r\n*/\r\nmodule.exports = (function () {\r\n\r\n let editor = codex.editor;\r\n\r\n /**\r\n * Initialize plugins before using\r\n * Ex. Load scripts or call some internal methods\r\n * @return Promise\r\n */\r\n function prepare() {\r\n\r\n return new Promise(function (resolve_, reject_) {\r\n\r\n Promise.resolve()\r\n\r\n /**\r\n * Compose a sequence of plugins that requires preparation\r\n */\r\n .then(function () {\r\n\r\n let pluginsRequiresPreparation = [],\r\n allPlugins = editor.tools;\r\n\r\n for ( let pluginName in allPlugins ) {\r\n\r\n let plugin = allPlugins[pluginName];\r\n\r\n if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {\r\n\r\n continue;\r\n\r\n }\r\n\r\n pluginsRequiresPreparation.push(plugin);\r\n\r\n }\r\n\r\n /**\r\n * If no one passed plugins requires preparation, finish prepare() and go ahead\r\n */\r\n if (!pluginsRequiresPreparation.length) {\r\n\r\n resolve_();\r\n\r\n }\r\n\r\n return pluginsRequiresPreparation;\r\n\r\n })\r\n\r\n /** Wait plugins while they prepares */\r\n .then(waitAllPluginsPreparation_)\r\n\r\n .then(function () {\r\n\r\n editor.core.log('Plugins loaded', 'info');\r\n resolve_();\r\n\r\n }).catch(function (error) {\r\n\r\n reject_(error);\r\n\r\n });\r\n\r\n });\r\n\r\n }\r\n\r\n /**\r\n * @param {array} plugins - list of tools that requires preparation\r\n * @return {Promise} resolved while all plugins will be ready or failed\r\n */\r\n function waitAllPluginsPreparation_(plugins) {\r\n\r\n /**\r\n * @calls allPluginsProcessed__ when all plugins prepared or failed\r\n */\r\n return new Promise (function (allPluginsProcessed__) {\r\n\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 * If last plugin is \"prepared\" then go to the next stage of initialization\r\n */\r\n plugins.reduce(function (previousValue, plugin, iteration) {\r\n\r\n return previousValue.then(function () {\r\n\r\n /**\r\n * Wait till plugins prepared\r\n * @calls pluginIsReady__ when plugin is ready or failed\r\n */\r\n return new Promise ( function (pluginIsReady__) {\r\n\r\n callPluginsPrepareMethod_( plugin )\r\n\r\n .then( pluginIsReady__ )\r\n .then( function () {\r\n\r\n plugin.available = true;\r\n\r\n })\r\n\r\n .catch(function (error) {\r\n\r\n editor.core.log(`Plugin «${plugin.type}» was not loaded. Preparation failed because %o`, 'warn', error);\r\n plugin.available = false;\r\n plugin.loadingMessage = error;\r\n\r\n /** Go ahead even some plugin has problems */\r\n pluginIsReady__();\r\n\r\n })\r\n\r\n .then(function () {\r\n\r\n /** If last plugin has problems then just ignore and continue */\r\n if (iteration == plugins.length - 1) {\r\n\r\n allPluginsProcessed__();\r\n\r\n }\r\n\r\n });\r\n\r\n });\r\n\r\n });\r\n\r\n }, Promise.resolve() );\r\n\r\n });\r\n\r\n }\r\n\r\n var callPluginsPrepareMethod_ = function (plugin) {\r\n\r\n return plugin.prepare( plugin.config || {} );\r\n\r\n };\r\n\r\n return {\r\n prepare: prepare\r\n };\r\n\r\n}());\n\n\n// WEBPACK FOOTER //\n// ./modules/tools.js","/**\r\n * Codex Editor UI module\r\n *\r\n * @author Codex Team\r\n * @version 1.1\r\n */\r\n\r\nmodule.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.className = {\r\n\r\n /**\r\n * @const {string} BLOCK_CLASSNAME - redactor blocks name\r\n */\r\n BLOCK_CLASSNAME : 'ce-block',\r\n\r\n /**\r\n * @const {String} wrapper for plugins content\r\n */\r\n BLOCK_CONTENT : 'ce-block__content',\r\n\r\n /**\r\n * @const {String} BLOCK_STRETCHED - makes block stretched\r\n */\r\n BLOCK_STRETCHED : 'ce-block--stretched',\r\n\r\n /**\r\n * @const {String} BLOCK_HIGHLIGHTED - adds background\r\n */\r\n BLOCK_HIGHLIGHTED : 'ce-block--focused',\r\n\r\n /**\r\n * @const {String} - highlights covered blocks\r\n */\r\n BLOCK_IN_FEED_MODE : 'ce-block--feed-mode',\r\n\r\n /**\r\n * @const {String} - Block with anchor\r\n */\r\n BLOCK_WITH_ANCHOR : 'ce-block--anchor',\r\n\r\n /**\r\n * @const {String} - for all default settings\r\n */\r\n SETTINGS_ITEM : 'ce-settings__item'\r\n\r\n };\r\n\r\n /**\r\n * @protected\r\n *\r\n * Making main interface\r\n */\r\n ui.make = function () {\r\n\r\n var wrapper,\r\n toolbar,\r\n toolbarContent,\r\n redactor,\r\n blockButtons,\r\n blockSettings,\r\n showSettingsButton,\r\n showTrashButton,\r\n toolbox,\r\n plusButton;\r\n\r\n /** Make editor wrapper */\r\n wrapper = editor.draw.wrapper();\r\n\r\n /** Append editor wrapper after initial textarea */\r\n editor.core.insertAfter(editor.nodes.textarea, wrapper);\r\n\r\n /** Append block with notifications to the document */\r\n editor.notifications.createHolder();\r\n\r\n /** Make toolbar and content-editable redactor */\r\n toolbar = editor.draw.toolbar();\r\n toolbarContent = editor.draw.toolbarContent();\r\n plusButton = editor.draw.plusButton();\r\n showSettingsButton = editor.draw.settingsButton();\r\n showTrashButton = editor.toolbar.settings.makeRemoveBlockButton();\r\n blockSettings = editor.draw.blockSettings();\r\n blockButtons = editor.draw.blockButtons();\r\n toolbox = editor.draw.toolbox();\r\n redactor = editor.draw.redactor();\r\n\r\n /** settings */\r\n var defaultSettings = editor.draw.defaultSettings(),\r\n pluginSettings = editor.draw.pluginsSettings();\r\n\r\n /** Add default and plugins settings */\r\n blockSettings.appendChild(pluginSettings);\r\n blockSettings.appendChild(defaultSettings);\r\n\r\n /** Make blocks buttons\r\n * This block contains settings button and remove block button\r\n */\r\n blockButtons.appendChild(showSettingsButton);\r\n blockButtons.appendChild(showTrashButton);\r\n blockButtons.appendChild(blockSettings);\r\n\r\n /** Append plus button */\r\n toolbarContent.appendChild(plusButton);\r\n\r\n /** Appending toolbar tools */\r\n toolbarContent.appendChild(toolbox);\r\n\r\n /** Appending first-level block buttons */\r\n toolbar.appendChild(blockButtons);\r\n\r\n /** Append toolbarContent to toolbar */\r\n toolbar.appendChild(toolbarContent);\r\n\r\n wrapper.appendChild(toolbar);\r\n\r\n wrapper.appendChild(redactor);\r\n\r\n /** Save created ui-elements to static nodes state */\r\n editor.nodes.wrapper = wrapper;\r\n editor.nodes.toolbar = toolbar;\r\n editor.nodes.plusButton = plusButton;\r\n editor.nodes.toolbox = toolbox;\r\n editor.nodes.blockSettings = blockSettings;\r\n editor.nodes.pluginSettings = pluginSettings;\r\n editor.nodes.defaultSettings = defaultSettings;\r\n editor.nodes.showSettingsButton = showSettingsButton;\r\n editor.nodes.showTrashButton = showTrashButton;\r\n\r\n editor.nodes.redactor = redactor;\r\n\r\n /** Make container for inline toolbar */\r\n editor.ui.makeInlineToolbar();\r\n\r\n /** fill in default settings */\r\n editor.toolbar.settings.addDefaultSettings();\r\n\r\n };\r\n\r\n ui.makeInlineToolbar = function () {\r\n\r\n var container = editor.draw.inlineToolbar();\r\n\r\n /** Append to redactor new inline block */\r\n editor.nodes.inlineToolbar.wrapper = container;\r\n\r\n /** Draw toolbar buttons */\r\n editor.nodes.inlineToolbar.buttons = editor.draw.inlineToolbarButtons();\r\n\r\n /** Buttons action or settings */\r\n editor.nodes.inlineToolbar.actions = editor.draw.inlineToolbarActions();\r\n\r\n /** Append to inline toolbar buttons as part of it */\r\n editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.buttons);\r\n editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.actions);\r\n\r\n editor.nodes.wrapper.appendChild(editor.nodes.inlineToolbar.wrapper);\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n * Append tools passed in editor.tools\r\n */\r\n ui.addTools = function () {\r\n\r\n var tool,\r\n toolName,\r\n toolButton;\r\n\r\n for ( toolName in editor.settings.tools ) {\r\n\r\n tool = editor.settings.tools[toolName];\r\n\r\n editor.tools[toolName] = tool;\r\n\r\n if (!tool.iconClassname) {\r\n\r\n editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\r\n continue;\r\n\r\n }\r\n\r\n if (typeof tool.render != 'function') {\r\n\r\n editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\r\n continue;\r\n\r\n }\r\n\r\n if (!tool.displayInToolbox) {\r\n\r\n continue;\r\n\r\n } else {\r\n\r\n /** if tools is for toolbox */\r\n toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\r\n\r\n editor.nodes.toolbox.appendChild(toolButton);\r\n\r\n editor.nodes.toolbarButtons[toolName] = toolButton;\r\n\r\n }\r\n\r\n }\r\n\r\n /**\r\n * Add inline toolbar tools\r\n */\r\n editor.ui.addInlineToolbarTools();\r\n\r\n\r\n };\r\n\r\n ui.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 underline: {\r\n icon : 'ce-icon-underline',\r\n command : 'underline'\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 ui.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 /**\r\n * @deprecated ( but now in use for syncronization );\r\n * Any redactor changes: keyboard input, mouse cut/paste, drag-n-drop text\r\n */\r\n // editor.nodes.redactor.addEventListener('input', editor.callback.redactorInputEvent, 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.callback.blockPasteCallback, false);\r\n\r\n editor.listeners.add(block, 'mouseup', 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 /** Save all inputs in global variable state */\r\n editor.state.inputs = redactor.querySelectorAll('[contenteditable], input');\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', 'Расскажите свою историю...');\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})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/ui.js","/**\r\n *\r\n * Codex.Editor Transport Module\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = (function (transport) {\r\n\r\n let editor = codex.editor;\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 transport.prepare = function () {\r\n\r\n var input = document.createElement('INPUT');\r\n\r\n input.type = 'file';\r\n editor.listeners.add(input, 'change', editor.transport.fileSelected);\r\n\r\n editor.transport.input = input;\r\n\r\n };\r\n\r\n /** Clear input when files is uploaded */\r\n transport.clearInput = function () {\r\n\r\n /** Remove old input */\r\n this.input = null;\r\n\r\n /** Prepare new one */\r\n this.prepare();\r\n\r\n };\r\n\r\n /**\r\n * Callback for file selection\r\n * @param {Event} event\r\n */\r\n transport.fileSelected = function () {\r\n\r\n var input = this,\r\n files = input.files,\r\n formdData = new FormData();\r\n\r\n formdData.append('files', files[0], files[0].name);\r\n\r\n editor.transport.ajax({\r\n data : formdData,\r\n beforeSend : editor.transport.arguments.beforeSend,\r\n success : editor.transport.arguments.success,\r\n error : editor.transport.arguments.error\r\n });\r\n\r\n };\r\n\r\n /**\r\n * Use plugin callbacks\r\n * @protected\r\n */\r\n transport.selectAndUpload = function (args) {\r\n\r\n this.arguments = args;\r\n this.input.click();\r\n\r\n };\r\n\r\n /**\r\n * Ajax requests module\r\n * @todo use core.ajax\r\n */\r\n transport.ajax = function (params) {\r\n\r\n var xhr = new XMLHttpRequest(),\r\n beforeSend = typeof params.beforeSend == 'function' ? params.beforeSend : function () {},\r\n success = typeof params.success == 'function' ? params.success : function () {},\r\n error = typeof params.error == 'function' ? params.error : function () {};\r\n\r\n beforeSend();\r\n\r\n xhr.open('POST', editor.settings.uploadImagesUrl, true);\r\n\r\n xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\r\n\r\n xhr.onload = function () {\r\n\r\n if (xhr.status === 200) {\r\n\r\n success(xhr.responseText);\r\n\r\n } else {\r\n\r\n editor.core.log('request error: %o', xhr);\r\n error();\r\n\r\n }\r\n\r\n };\r\n\r\n xhr.send(params.data);\r\n this.clearInput();\r\n\r\n };\r\n\r\n return transport;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/transport.js","/**\r\n * Codex Editor Renderer Module\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = (function (renderer) {\r\n\r\n let editor = codex.editor;\r\n\r\n /**\r\n * Asyncronously parses input JSON to redactor blocks\r\n */\r\n renderer.makeBlocksFromData = function () {\r\n\r\n /**\r\n * If redactor is empty, add first paragraph to start writing\r\n */\r\n if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {\r\n\r\n editor.ui.addInitialBlock();\r\n return;\r\n\r\n }\r\n\r\n Promise.resolve()\r\n\r\n /** First, get JSON from state */\r\n .then(function () {\r\n\r\n return editor.state.blocks;\r\n\r\n })\r\n\r\n /** Then, start to iterate they */\r\n .then(editor.renderer.appendBlocks)\r\n\r\n /** Write log if something goes wrong */\r\n .catch(function (error) {\r\n\r\n editor.core.log('Error while parsing JSON: %o', 'error', error);\r\n\r\n });\r\n\r\n };\r\n\r\n /**\r\n * Parses JSON to blocks\r\n * @param {object} data\r\n * @return Primise -> nodeList\r\n */\r\n renderer.appendBlocks = function (data) {\r\n\r\n var blocks = data.items;\r\n\r\n /**\r\n * Sequence of one-by-one blocks appending\r\n * Uses to save blocks order after async-handler\r\n */\r\n var nodeSequence = Promise.resolve();\r\n\r\n for (var index = 0; index < blocks.length ; index++ ) {\r\n\r\n /** Add node to sequence at specified index */\r\n editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Append node at specified index\r\n */\r\n renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\r\n\r\n /** We need to append node to sequence */\r\n nodeSequence\r\n\r\n /** first, get node async-aware */\r\n .then(function () {\r\n\r\n return editor.renderer.getNodeAsync(blocks, index);\r\n\r\n })\r\n\r\n /**\r\n * second, compose editor-block from JSON object\r\n */\r\n .then(editor.renderer.createBlockFromData)\r\n\r\n /**\r\n * now insert block to redactor\r\n */\r\n .then(function (blockData) {\r\n\r\n /**\r\n * blockData has 'block', 'type' and 'stretched' information\r\n */\r\n editor.content.insertBlock(blockData);\r\n\r\n /** Pass created block to next step */\r\n return blockData.block;\r\n\r\n })\r\n\r\n /** Log if something wrong with node */\r\n .catch(function (error) {\r\n\r\n editor.core.log('Node skipped while parsing because %o', 'error', error);\r\n\r\n });\r\n\r\n };\r\n\r\n /**\r\n * Asynchronously returns block data from blocksList by index\r\n * @return Promise to node\r\n */\r\n renderer.getNodeAsync = function (blocksList, index) {\r\n\r\n return Promise.resolve().then(function () {\r\n\r\n return {\r\n tool : blocksList[index],\r\n position : index\r\n };\r\n\r\n });\r\n\r\n };\r\n\r\n /**\r\n * Creates editor block by JSON-data\r\n *\r\n * @uses render method of each plugin\r\n *\r\n * @param {Object} toolData.tool\r\n * { header : {\r\n * text: '',\r\n * type: 'H3', ...\r\n * }\r\n * }\r\n * @param {Number} toolData.position - index in input-blocks array\r\n * @return {Object} with type and Element\r\n */\r\n renderer.createBlockFromData = function ( toolData ) {\r\n\r\n /** New parser */\r\n var block,\r\n tool = toolData.tool,\r\n pluginName = tool.type,\r\n anchor = tool.anchor,\r\n cover = tool.cover;\r\n\r\n /** Get first key of object that stores plugin name */\r\n // for (var pluginName in blockData) break;\r\n\r\n /** Check for plugin existance */\r\n if (!editor.tools[pluginName]) {\r\n\r\n throw Error(`Plugin «${pluginName}» not found`);\r\n\r\n }\r\n\r\n /** Check for plugin having render method */\r\n if (typeof editor.tools[pluginName].render != 'function') {\r\n\r\n throw Error(`Plugin «${pluginName}» must have «render» method`);\r\n\r\n }\r\n\r\n if ( editor.tools[pluginName].available === false ) {\r\n\r\n block = editor.draw.unavailableBlock();\r\n\r\n block.innerHTML = editor.tools[pluginName].loadingMessage;\r\n\r\n /**\r\n * Saver will extract data from initial block data by position in array\r\n */\r\n block.dataset.inputPosition = toolData.position;\r\n\r\n } else {\r\n\r\n /** New Parser */\r\n block = editor.tools[pluginName].render(tool.data);\r\n\r\n }\r\n\r\n /** is first-level block stretched */\r\n var stretched = editor.tools[pluginName].isStretched || false;\r\n\r\n /** Retrun type and block */\r\n return {\r\n type : pluginName,\r\n block : block,\r\n stretched : stretched,\r\n cover : cover,\r\n anchor : anchor\r\n };\r\n\r\n };\r\n\r\n return renderer;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/renderer.js","/**\r\n * Codex Editor Saver\r\n *\r\n * @author Codex Team\r\n * @version 1.0.2\r\n */\r\n\r\nmodule.exports = (function (saver) {\r\n\r\n let editor = codex.editor;\r\n\r\n /**\r\n * Saves blocks\r\n * @private\r\n */\r\n saver.saveBlocks = 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 /** Empty jsonOutput state */\r\n editor.state.jsonOutput = [];\r\n\r\n Promise.resolve()\r\n\r\n .then(function () {\r\n\r\n return editor.nodes.redactor.childNodes;\r\n\r\n })\r\n /** Making a sequence from separate blocks */\r\n .then(editor.saver.makeQueue)\r\n\r\n .then(function () {\r\n // editor.nodes.textarea.innerHTML = editor.state.html;\r\n })\r\n\r\n .catch( function (error) {\r\n\r\n editor.core.log(error);\r\n\r\n });\r\n\r\n };\r\n\r\n saver.makeQueue = function (blocks) {\r\n\r\n var queue = Promise.resolve();\r\n\r\n for(var index = 0; index < blocks.length; index++) {\r\n\r\n /** Add node to sequence at specified index */\r\n editor.saver.getBlockData(queue, blocks, index);\r\n\r\n }\r\n\r\n };\r\n\r\n /** Gets every block and makes From Data */\r\n saver.getBlockData = function (queue, blocks, index) {\r\n\r\n queue.then(function () {\r\n\r\n return editor.saver.getNodeAsync(blocks, index);\r\n\r\n })\r\n\r\n .then(editor.saver.makeFormDataFromBlocks);\r\n\r\n };\r\n\r\n\r\n /**\r\n * Asynchronously returns block data from blocksList by index\r\n * @return Promise to node\r\n */\r\n saver.getNodeAsync = function (blocksList, index) {\r\n\r\n return Promise.resolve().then(function () {\r\n\r\n return blocksList[index];\r\n\r\n });\r\n\r\n };\r\n\r\n saver.makeFormDataFromBlocks = function (block) {\r\n\r\n var pluginName = block.dataset.tool,\r\n anchor = block.dataset.anchor;\r\n\r\n /** Check for plugin existance */\r\n if (!editor.tools[pluginName]) {\r\n\r\n throw Error(`Plugin «${pluginName}» not found`);\r\n\r\n }\r\n\r\n /** Check for plugin having render method */\r\n if (typeof editor.tools[pluginName].save != 'function') {\r\n\r\n throw Error(`Plugin «${pluginName}» must have save method`);\r\n\r\n }\r\n\r\n /** Result saver */\r\n var blockContent = block.childNodes[0],\r\n pluginsContent = blockContent.childNodes[0],\r\n savedData,\r\n position,\r\n output,\r\n coverFlag = false;\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 position = pluginsContent.dataset.inputPosition;\r\n\r\n savedData = codex.editor.state.blocks.items[position].data;\r\n coverFlag = codex.editor.state.blocks.items[position].cover;\r\n anchor = codex.editor.state.blocks.items[position].anchor;\r\n\r\n } else {\r\n\r\n savedData = editor.tools[pluginName].save(pluginsContent);\r\n coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\r\n\r\n if (editor.tools[pluginName].validate) {\r\n\r\n var result = editor.tools[pluginName].validate(savedData);\r\n\r\n /**\r\n * Do not allow invalid data\r\n */\r\n if (!result)\r\n return;\r\n\r\n }\r\n\r\n }\r\n\r\n output = {\r\n type : pluginName,\r\n anchor : anchor,\r\n data : savedData\r\n };\r\n\r\n /** Marks Blocks that will be in main page */\r\n output.cover = coverFlag;\r\n\r\n editor.state.jsonOutput.push(output);\r\n\r\n };\r\n\r\n return saver;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/saver.js","/**\r\n * Codex Editor Content Module\r\n * Works with DOM\r\n *\r\n * @author Codex Team\r\n * @version 1.3.11\r\n */\r\n\r\nmodule.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 * 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 * @deprecated\r\n */\r\n content.getNodeFocused = function () {\r\n\r\n var selection = window.getSelection(),\r\n focused;\r\n\r\n if (selection.anchorNode === null) {\r\n\r\n return null;\r\n\r\n }\r\n\r\n if ( selection.anchorNode.nodeType == editor.core.nodeTypes.TAG ) {\r\n\r\n focused = selection.anchorNode;\r\n\r\n } else {\r\n\r\n focused = selection.focusNode.parentElement;\r\n\r\n }\r\n\r\n if ( !editor.parser.isFirstLevelBlock(focused) ) {\r\n\r\n /** Iterate with parent nodes to find first-level*/\r\n var parent = focused.parentNode;\r\n\r\n while (parent && !editor.parser.isFirstLevelBlock(parent)) {\r\n\r\n parent = parent.parentNode;\r\n\r\n }\r\n\r\n focused = parent;\r\n\r\n }\r\n\r\n if (focused != editor.nodes.redactor) {\r\n\r\n return focused;\r\n\r\n }\r\n\r\n return null;\r\n\r\n };\r\n\r\n /**\r\n * Appends background to the block\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 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 * @private\r\n *\r\n * Finds first-level block\r\n * @param {Element} node - selected or clicked in redactors area node\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 * 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 this.currentNode = this.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 /**\r\n * Check is this block was in feed\r\n * If true, than set switched block also covered\r\n */\r\n if (targetBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE)) {\r\n\r\n newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\r\n\r\n }\r\n\r\n if (targetBlock.classList.contains(editor.ui.className.BLOCK_WITH_ANCHOR)) {\r\n\r\n newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\r\n\r\n }\r\n\r\n /**\r\n * Saving anchor\r\n */\r\n newBlock.dataset.anchor = targetBlock.dataset.anchor;\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 * @private\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 cover = blockData.cover,\r\n anchor = blockData.anchor,\r\n isStretched = blockData.stretched;\r\n\r\n var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);\r\n\r\n if (cover === true) {\r\n\r\n newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\r\n\r\n }\r\n\r\n if (anchor) {\r\n\r\n newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\r\n\r\n }\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 var newBlockComposed = editor.content.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 * @private\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 */\r\n content.composeNewBlock = function (block, tool, isStretched, anchor) {\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 newBlock.dataset.anchor = anchor || '';\r\n return newBlock;\r\n\r\n };\r\n\r\n /**\r\n * Returns Range object of current selection\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 * @private\r\n * @param {Int} inputIndex - target input index\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 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 * @private\r\n *\r\n * Callback for HTML Mutations\r\n * @param {Array} mutation - Mutation Record\r\n */\r\n content.paste = function (mutation) {\r\n\r\n var workingNode = editor.content.currentNode,\r\n tool = workingNode.dataset.tool;\r\n\r\n if (editor.tools[tool].allowedToPaste) {\r\n\r\n editor.content.sanitize.call(this, mutation.target);\r\n\r\n } else {\r\n\r\n editor.content.pasteTextContent(mutation.addedNodes);\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * gets only text/plain content of node\r\n * @param {Element} target - HTML node\r\n */\r\n content.pasteTextContent = function (nodes) {\r\n\r\n var node = nodes[0],\r\n textNode;\r\n\r\n if (!node) {\r\n\r\n return;\r\n\r\n }\r\n\r\n if (node.nodeType == editor.core.nodeTypes.TEXT) {\r\n\r\n textNode = document.createTextNode(node);\r\n\r\n } else {\r\n\r\n textNode = document.createTextNode(node.textContent);\r\n\r\n }\r\n\r\n if (editor.core.isDomNode(node)) {\r\n\r\n node.parentNode.replaceChild(textNode, node);\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Sanitizes HTML content\r\n * @param {Element} target - inserted element\r\n * @uses Sanitize library html-janitor\r\n */\r\n content.sanitize = function (target) {\r\n\r\n if (!target) {\r\n\r\n return;\r\n\r\n }\r\n\r\n var node = target[0];\r\n\r\n if (!node) {\r\n\r\n return;\r\n\r\n }\r\n\r\n /**\r\n * Disconnect Observer\r\n * hierarchy of function calls inherits context of observer\r\n */\r\n this.disconnect();\r\n\r\n /**\r\n * Don't sanitize text node\r\n */\r\n if (node.nodeType == editor.core.nodeTypes.TEXT) {\r\n\r\n return;\r\n\r\n }\r\n\r\n /**\r\n * Clear dirty content\r\n */\r\n var cleaner = editor.sanitizer.init(editor.satinizer.Config.BASIC),\r\n clean = cleaner.clean(target.outerHTML);\r\n\r\n var div = editor.draw.node('DIV', [], { innerHTML: clean });\r\n\r\n node.replaceWith(div.childNodes[0]);\r\n\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] htmlString - html content as string\r\n * @return {string} - html content as string\r\n */\r\n content.wrapTextWithParagraphs = function (htmlString) {\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 = htmlString;\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 * 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 return content;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/content.js","/**\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) {\r\n\r\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 () {\r\n\r\n if (editor.hideToolbar) {\r\n\r\n return;\r\n\r\n }\r\n\r\n editor.nodes.toolbar.classList.add('opened');\r\n this.opened = true;\r\n\r\n };\r\n\r\n /**\r\n * @protected\r\n */\r\n toolbar.close = function () {\r\n\r\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) {\r\n\r\n editor.nodes.toolbarButtons[button].classList.remove('selected');\r\n\r\n }\r\n\r\n /** Close toolbox when toolbar is not displayed */\r\n editor.toolbar.toolbox.close();\r\n editor.toolbar.settings.close();\r\n\r\n };\r\n\r\n toolbar.toggle = function () {\r\n\r\n if ( !this.opened ) {\r\n\r\n this.open();\r\n\r\n } else {\r\n\r\n this.close();\r\n\r\n }\r\n\r\n };\r\n\r\n toolbar.hidePlusButton = function () {\r\n\r\n editor.nodes.plusButton.classList.add('hide');\r\n\r\n };\r\n\r\n toolbar.showPlusButton = function () {\r\n\r\n editor.nodes.plusButton.classList.remove('hide');\r\n\r\n };\r\n\r\n /**\r\n * Moving toolbar to the specified node\r\n */\r\n toolbar.move = function () {\r\n\r\n /** Close Toolbox when we move toolbar */\r\n editor.toolbar.toolbox.close();\r\n\r\n if (!editor.content.currentNode) {\r\n\r\n return;\r\n\r\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();\r\n\r\n };\r\n\r\n return toolbar;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/toolbar.js","/**\r\n * Toolbar settings\r\n *\r\n * @version 1.0.4\r\n */\r\n\r\nmodule.exports = (function (settings) {\r\n\r\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 settings.cover = null;\r\n\r\n /**\r\n * Append and open settings\r\n */\r\n settings.open = function (toolType) {\r\n\r\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 ) {\r\n\r\n editor.core.log(`Plugin «${toolType}» has no settings`, 'warn');\r\n // editor.nodes.pluginSettings.innerHTML = `Плагин «${toolType}» не имеет настроек`;\r\n\r\n } else {\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\r\n /** Open settings block */\r\n editor.nodes.blockSettings.classList.add('opened');\r\n editor.toolbar.settings.addDefaultSettings();\r\n this.opened = true;\r\n\r\n };\r\n\r\n /**\r\n * Close and clear settings\r\n */\r\n settings.close = function () {\r\n\r\n editor.nodes.blockSettings.classList.remove('opened');\r\n editor.nodes.pluginSettings.innerHTML = '';\r\n\r\n this.opened = false;\r\n\r\n };\r\n\r\n /**\r\n * @param {string} toolType - plugin type\r\n */\r\n settings.toggle = function ( toolType ) {\r\n\r\n if ( !this.opened ) {\r\n\r\n this.open(toolType);\r\n editor.anchors.settingsOpened(editor.content.currentNode);\r\n\r\n } else {\r\n\r\n this.close();\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * This function adds default core settings\r\n */\r\n settings.addDefaultSettings = function () {\r\n\r\n /** list of default settings */\r\n var feedModeToggler,\r\n anchorInput;\r\n\r\n /** Clear block and append initialized settings */\r\n editor.nodes.defaultSettings.innerHTML = '';\r\n\r\n\r\n /** Init all default setting buttons */\r\n feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();\r\n anchorInput = editor.toolbar.settings.makeAnchorInput();\r\n\r\n /**\r\n * Fill defaultSettings\r\n */\r\n\r\n /**\r\n * Input for anchor for block\r\n */\r\n editor.nodes.defaultSettings.appendChild(anchorInput);\r\n\r\n /**\r\n * Button that enables/disables Feed-mode\r\n * Feed-mode means that block will be showed in articles-feed like cover\r\n */\r\n editor.nodes.defaultSettings.appendChild(feedModeToggler);\r\n\r\n };\r\n\r\n /**\r\n * Cover setting.\r\n * This tune highlights block, so that it may be used for showing target block on main page\r\n * Draw different setting when block is marked for main page\r\n * If TRUE, then we show button that removes this selection\r\n * Also defined setting \"Click\" events will be listened and have separate callbacks\r\n *\r\n * @return {Element} node/button that we place in default settings block\r\n */\r\n settings.makeFeedModeToggler = function () {\r\n\r\n var isFeedModeActivated = editor.toolbar.settings.isFeedModeActivated(),\r\n setting,\r\n data;\r\n\r\n if (!isFeedModeActivated) {\r\n\r\n data = {\r\n innerHTML : '<i class=\"ce-icon-newspaper\"></i>Вывести в ленте'\r\n };\r\n\r\n } else {\r\n\r\n data = {\r\n innerHTML : '<i class=\"ce-icon-newspaper\"></i>Не выводить в ленте'\r\n };\r\n\r\n }\r\n\r\n setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\r\n editor.listeners.add(setting, 'click', editor.toolbar.settings.updateFeedMode, false);\r\n\r\n return setting;\r\n\r\n };\r\n\r\n /**\r\n * Updates Feed-mode\r\n */\r\n settings.updateFeedMode = function () {\r\n\r\n var currentNode = editor.content.currentNode;\r\n\r\n currentNode.classList.toggle(editor.ui.className.BLOCK_IN_FEED_MODE);\r\n\r\n editor.toolbar.settings.close();\r\n\r\n };\r\n\r\n settings.isFeedModeActivated = function () {\r\n\r\n var currentBlock = editor.content.currentNode;\r\n\r\n if (currentBlock) {\r\n\r\n return currentBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\r\n\r\n } else {\r\n\r\n return false;\r\n\r\n }\r\n\r\n };\r\n\r\n settings.makeAnchorInput = function () {\r\n\r\n var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),\r\n hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),\r\n anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });\r\n\r\n editor.listeners.add(anchor, 'keydown', editor.anchors.keyDownOnAnchorInput );\r\n editor.listeners.add(anchor, 'keyup', editor.anchors.keyUpOnAnchorInput );\r\n editor.listeners.add(anchor, 'input', editor.anchors.anchorChanged );\r\n editor.listeners.add(anchor, 'blur', editor.anchors.anchorChanged );\r\n\r\n anchorWrapper.appendChild(hash);\r\n anchorWrapper.appendChild(anchor);\r\n\r\n editor.anchors.input = anchor;\r\n\r\n return anchorWrapper;\r\n\r\n };\r\n\r\n /**\r\n * Here we will draw buttons and add listeners to components\r\n */\r\n settings.makeRemoveBlockButton = function () {\r\n\r\n var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}),\r\n settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML : '<i class=\"ce-icon-trash\"></i>' }),\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;\r\n\r\n };\r\n\r\n settings.removeButtonClicked = function () {\r\n\r\n var action = editor.toolbar.settings.actions;\r\n\r\n if (action.classList.contains('opened')) {\r\n\r\n editor.toolbar.settings.hideRemoveActions();\r\n\r\n } else {\r\n\r\n editor.toolbar.settings.showRemoveActions();\r\n\r\n }\r\n\r\n editor.toolbar.toolbox.close();\r\n editor.toolbar.settings.close();\r\n\r\n };\r\n\r\n settings.cancelRemovingRequest = function () {\r\n\r\n editor.toolbar.settings.actions.classList.remove('opened');\r\n\r\n };\r\n\r\n settings.confirmRemovingRequest = function () {\r\n\r\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) {\r\n\r\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 }\r\n\r\n editor.ui.saveInputs();\r\n\r\n editor.toolbar.close();\r\n\r\n };\r\n\r\n settings.showRemoveActions = function () {\r\n\r\n editor.toolbar.settings.actions.classList.add('opened');\r\n\r\n };\r\n\r\n settings.hideRemoveActions = function () {\r\n\r\n editor.toolbar.settings.actions.classList.remove('opened');\r\n\r\n };\r\n\r\n return settings;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/settings.js","/**\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) {\r\n\r\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 () {\r\n\r\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) {\r\n\r\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();\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * @protected\r\n *\r\n * Closes inline toolbar\r\n */\r\n inline.close = function () {\r\n\r\n var toolbar = editor.nodes.inlineToolbar.wrapper;\r\n\r\n toolbar.classList.remove('opened');\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Moving toolbar\r\n */\r\n inline.move = function () {\r\n\r\n if (!this.wrappersOffset) {\r\n\r\n this.wrappersOffset = this.getWrappersOffset();\r\n\r\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) {\r\n\r\n defaultOffset = 40;\r\n\r\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();\r\n\r\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) {\r\n\r\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) {\r\n case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break;\r\n default : editor.toolbar.inline.defaultToolAction(type); break;\r\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);\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Saving wrappers offset in DOM\r\n */\r\n inline.getWrappersOffset = function () {\r\n\r\n var wrapper = editor.nodes.wrapper,\r\n offset = this.getOffset(wrapper);\r\n\r\n this.wrappersOffset = offset;\r\n return offset;\r\n\r\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 ) {\r\n\r\n var _x = 0;\r\n var _y = 0;\r\n\r\n while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {\r\n\r\n _x += (el.offsetLeft + el.clientLeft);\r\n _y += (el.offsetTop + el.clientTop);\r\n el = el.offsetParent;\r\n\r\n }\r\n return { top: _y, left: _x };\r\n\r\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 () {\r\n\r\n var sel = document.selection, range;\r\n var x = 0, y = 0;\r\n\r\n if (sel) {\r\n\r\n if (sel.type != 'Control') {\r\n\r\n range = sel.createRange();\r\n range.collapse(true);\r\n x = range.boundingLeft;\r\n y = range.boundingTop;\r\n\r\n }\r\n\r\n } else if (window.getSelection) {\r\n\r\n sel = window.getSelection();\r\n\r\n if (sel.rangeCount) {\r\n\r\n range = sel.getRangeAt(0).cloneRange();\r\n if (range.getClientRects) {\r\n\r\n range.collapse(true);\r\n var rect = range.getClientRects()[0];\r\n\r\n if (!rect) {\r\n\r\n return;\r\n\r\n }\r\n\r\n x = rect.left;\r\n y = rect.top;\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n return { x: x, y: y };\r\n\r\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 () {\r\n\r\n var selectedText = '';\r\n\r\n // all modern browsers and IE9+\r\n if (window.getSelection) {\r\n\r\n selectedText = window.getSelection().toString();\r\n\r\n }\r\n\r\n return selectedText;\r\n\r\n };\r\n\r\n /** Opens buttons block */\r\n inline.showButtons = function () {\r\n\r\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);\r\n\r\n };\r\n\r\n /** Makes buttons disappear */\r\n inline.closeButtons = function () {\r\n\r\n var buttons = editor.nodes.inlineToolbar.buttons;\r\n\r\n buttons.classList.remove('opened');\r\n\r\n editor.toolbar.inline.buttonsOpened = false;\r\n\r\n };\r\n\r\n /** Open buttons defined action if exist */\r\n inline.showActions = function () {\r\n\r\n var action = editor.nodes.inlineToolbar.actions;\r\n\r\n action.classList.add('opened');\r\n\r\n editor.toolbar.inline.actionsOpened = true;\r\n\r\n };\r\n\r\n /** Close actions block */\r\n inline.closeAction = function () {\r\n\r\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;\r\n\r\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) {\r\n\r\n if (event.keyCode != editor.core.keys.ENTER) {\r\n\r\n return;\r\n\r\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();\r\n\r\n };\r\n\r\n /** Action for link creation or for setting anchor */\r\n inline.createLinkAction = function (event) {\r\n\r\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) {\r\n\r\n\r\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');\r\n\r\n } else {\r\n\r\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);\r\n\r\n }\r\n\r\n };\r\n\r\n inline.isLinkActive = function () {\r\n\r\n var isActive = false;\r\n\r\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\r\n\r\n var dataType = tool.dataset.type;\r\n\r\n if (dataType == 'link' && tool.classList.contains('hightlighted')) {\r\n\r\n isActive = true;\r\n\r\n }\r\n\r\n });\r\n\r\n return isActive;\r\n\r\n };\r\n\r\n /** default action behavior of tool */\r\n inline.defaultToolAction = function (type) {\r\n\r\n document.execCommand(type, false, null);\r\n\r\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) {\r\n\r\n document.execCommand('createLink', false, url);\r\n\r\n /** Close after URL inserting */\r\n editor.toolbar.inline.closeAction();\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Saves selection\r\n */\r\n inline.saveSelection = function (containerEl) {\r\n\r\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 };\r\n\r\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) {\r\n\r\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())) {\r\n\r\n if (node.nodeType == 3) {\r\n\r\n nextCharIndex = charIndex + node.length;\r\n\r\n if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\r\n\r\n range.setStart(node, savedSel.start - charIndex);\r\n foundStart = true;\r\n\r\n }\r\n if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\r\n\r\n range.setEnd(node, savedSel.end - charIndex);\r\n stop = true;\r\n\r\n }\r\n charIndex = nextCharIndex;\r\n\r\n } else {\r\n\r\n var i = node.childNodes.length;\r\n\r\n while (i--) {\r\n\r\n nodeStack.push(node.childNodes[i]);\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n var sel = window.getSelection();\r\n\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n\r\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 () {\r\n\r\n var selection = window.getSelection();\r\n\r\n selection.removeAllRanges();\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * sets or removes hightlight\r\n */\r\n inline.hightlight = function (tool) {\r\n\r\n var dataType = tool.dataset.type;\r\n\r\n if (document.queryCommandState(dataType)) {\r\n\r\n editor.toolbar.inline.setButtonHighlighted(tool);\r\n\r\n } else {\r\n\r\n editor.toolbar.inline.removeButtonsHighLight(tool);\r\n\r\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') {\r\n\r\n editor.toolbar.inline.setButtonHighlighted(tool);\r\n\r\n }\r\n\r\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) {\r\n\r\n button.classList.add('hightlighted');\r\n\r\n /** At link tool we also change icon */\r\n if (button.dataset.type == 'link') {\r\n\r\n var icon = button.childNodes[0];\r\n\r\n icon.classList.remove('ce-icon-link');\r\n icon.classList.add('ce-icon-unlink');\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * @private\r\n *\r\n * Removes hightlight\r\n */\r\n inline.removeButtonsHighLight = function (button) {\r\n\r\n button.classList.remove('hightlighted');\r\n\r\n /** At link tool we also change icon */\r\n if (button.dataset.type == 'link') {\r\n\r\n var icon = button.childNodes[0];\r\n\r\n icon.classList.remove('ce-icon-unlink');\r\n icon.classList.add('ce-icon-link');\r\n\r\n }\r\n\r\n };\r\n\r\n\r\n return inline;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/inline.js","/**\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) {\r\n\r\n let editor = codex.editor;\r\n\r\n toolbox.opened = false;\r\n\r\n /** Shows toolbox */\r\n toolbox.open = function () {\r\n\r\n /** Close setting if toolbox is opened */\r\n if (editor.toolbar.settings.opened) {\r\n\r\n editor.toolbar.settings.close();\r\n\r\n }\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;\r\n\r\n };\r\n\r\n /** Closes toolbox */\r\n toolbox.close = function () {\r\n\r\n /** Makes toolbox disapear */\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 };\r\n\r\n toolbox.leaf = function () {\r\n\r\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 ) {\r\n\r\n /** Get first tool from object*/\r\n for(tool in editor.tools) {\r\n\r\n if (editor.tools[tool].displayInToolbox) {\r\n\r\n break;\r\n\r\n }\r\n\r\n nextToolIndex ++;\r\n\r\n }\r\n\r\n } else {\r\n\r\n nextToolIndex = tools.indexOf(currentTool) + 1;\r\n visibleTool = tools[nextToolIndex];\r\n\r\n while (!editor.tools[visibleTool].displayInToolbox) {\r\n\r\n nextToolIndex++;\r\n visibleTool = tools[nextToolIndex];\r\n\r\n if ( nextToolIndex == tools.length ) {\r\n\r\n nextToolIndex = 0;\r\n visibleTool = tools[nextToolIndex];\r\n\r\n }\r\n\r\n }\r\n\r\n }\r\n\r\n toolToSelect = tools[nextToolIndex];\r\n\r\n for ( var button in barButtons ) {\r\n\r\n barButtons[button].classList.remove('selected');\r\n\r\n }\r\n\r\n barButtons[toolToSelect].classList.add('selected');\r\n editor.toolbar.current = toolToSelect;\r\n\r\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) {\r\n\r\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 ) {\r\n\r\n /** Replace current block */\r\n editor.content.switchBlock(workingNode, newBlockContent, tool.type);\r\n\r\n } else {\r\n\r\n /** Insert new Block from plugin */\r\n editor.content.insertBlock(blockData);\r\n\r\n /** increase input index */\r\n currentInputIndex++;\r\n\r\n }\r\n\r\n /** Fire tool append callback */\r\n appendCallback = tool.appendCallback;\r\n\r\n if (appendCallback && typeof appendCallback == 'function') {\r\n\r\n appendCallback.call(event);\r\n\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 /**\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();\r\n\r\n };\r\n\r\n return toolbox;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/toolbox.js","/**\r\n * Codex Editor callbacks module\r\n *\r\n * @author Codex Team\r\n * @version 1.3.7\r\n */\r\n\r\nmodule.exports = (function (callbacks) {\r\n\r\n let editor = codex.editor;\r\n\r\n callbacks.globalKeydown = function (event) {\r\n\r\n switch (event.keyCode) {\r\n case editor.core.keys.ENTER : editor.callback.enterKeyPressed(event); break;\r\n }\r\n\r\n };\r\n\r\n callbacks.redactorKeyDown = function (event) {\r\n\r\n switch (event.keyCode) {\r\n case editor.core.keys.TAB : editor.callback.tabKeyPressed(event); break;\r\n case editor.core.keys.ENTER : editor.callback.enterKeyPressedOnRedactorZone(event); break;\r\n case editor.core.keys.ESC : editor.callback.escapeKeyPressed(event); break;\r\n default : editor.callback.defaultKeyPressed(event); break;\r\n }\r\n\r\n };\r\n\r\n callbacks.globalKeyup = function (event) {\r\n\r\n switch (event.keyCode) {\r\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 : editor.callback.arrowKeyPressed(event); break;\r\n }\r\n\r\n };\r\n\r\n callbacks.tabKeyPressed = function (event) {\r\n\r\n var blockIsEmpty = !editor.content.currentNode.textContent.trim();\r\n\r\n if (!blockIsEmpty) {\r\n\r\n return;\r\n\r\n }\r\n\r\n if ( !editor.toolbar.opened ) {\r\n\r\n editor.toolbar.open();\r\n\r\n }\r\n\r\n if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\r\n\r\n editor.toolbar.toolbox.open();\r\n\r\n } else {\r\n\r\n editor.toolbar.toolbox.leaf();\r\n\r\n }\r\n\r\n event.preventDefault();\r\n\r\n };\r\n\r\n /**\r\n * @param {Event} event\r\n */\r\n callbacks.enterKeyPressed = function () {\r\n\r\n if (editor.content.editorAreaHightlighted) {\r\n\r\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 editor.callback.enterPressedOnBlock();\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * ENTER key handler\r\n * Makes new paragraph block\r\n */\r\n callbacks.enterKeyPressedOnRedactorZone = function (event) {\r\n\r\n if (event.target.contentEditable == 'true') {\r\n\r\n /** Update input index */\r\n editor.caret.saveCurrentInputIndex();\r\n\r\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 ) {\r\n\r\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;\r\n\r\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 ) {\r\n\r\n event.stopPropagation();\r\n event.stopImmediatePropagation();\r\n return;\r\n\r\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 <p> in same block by SHIFT+ENTER and forbids to prevent default browser behaviour\r\n */\r\n if ( event.shiftKey && !enableLineBreaks ) {\r\n\r\n editor.callback.enterPressedOnBlock(editor.content.currentBlock, event);\r\n event.preventDefault();\r\n return;\r\n\r\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 ) {\r\n\r\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()) {\r\n\r\n editor.toolbar.showPlusButton();\r\n\r\n }\r\n\r\n } else {\r\n\r\n var islastNode = editor.content.isLastNode(currentSelectedNode);\r\n\r\n if ( islastNode && caretAtTheEndOfText ) {\r\n\r\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();\r\n\r\n }\r\n\r\n }\r\n\r\n /** get all inputs after new appending block */\r\n editor.ui.saveInputs();\r\n\r\n };\r\n\r\n callbacks.escapeKeyPressed = function (event) {\r\n\r\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();\r\n\r\n };\r\n\r\n /**\r\n * @param {Event} event\r\n */\r\n callbacks.arrowKeyPressed = function () {\r\n\r\n editor.content.workingNodeChanged();\r\n\r\n /* Closing toolbar */\r\n editor.toolbar.close();\r\n editor.toolbar.move();\r\n\r\n };\r\n\r\n /**\r\n * @param {Event} event\r\n */\r\n callbacks.defaultKeyPressed = function () {\r\n\r\n editor.toolbar.close();\r\n\r\n if (!editor.toolbar.inline.actionsOpened) {\r\n\r\n editor.toolbar.inline.close();\r\n editor.content.clearMark();\r\n\r\n }\r\n\r\n };\r\n\r\n callbacks.redactorClicked = function (event) {\r\n\r\n callbacks.detectWhenClickedOnFirstLevelBlockArea();\r\n\r\n editor.content.workingNodeChanged(event.target);\r\n\r\n editor.ui.saveInputs();\r\n\r\n var selectedText = editor.toolbar.inline.getSelectionText(),\r\n firstLevelBlock;\r\n\r\n /**\r\n * If selection range took off, then we hide inline toolbar\r\n */\r\n if (selectedText.length === 0) {\r\n\r\n editor.toolbar.inline.close();\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 /**\r\n * @todo Refactor\r\n */\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 /**\r\n * Move toolbar to the right position and open\r\n */\r\n editor.toolbar.move();\r\n editor.toolbar.open();\r\n\r\n } else {\r\n\r\n /**\r\n * Move toolbar to the new position and open\r\n */\r\n editor.toolbar.move();\r\n editor.toolbar.open();\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 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) {\r\n\r\n /** Mark current block */\r\n editor.content.markBlock();\r\n\r\n }\r\n\r\n if ( isInitialType && inputIsEmpty ) {\r\n\r\n /** Show plus button */\r\n editor.toolbar.showPlusButton();\r\n\r\n }\r\n\r\n\r\n };\r\n\r\n /**\r\n * This method allows to define, is caret in contenteditable element or not.\r\n * 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 callbacks.detectWhenClickedOnFirstLevelBlockArea = function () {\r\n\r\n var selection = window.getSelection(),\r\n anchorNode = selection.anchorNode,\r\n flag = false;\r\n\r\n if (selection.rangeCount === 0) {\r\n\r\n editor.content.editorAreaHightlighted = true;\r\n\r\n } else {\r\n\r\n if (!editor.core.isDomNode(anchorNode)) {\r\n\r\n anchorNode = anchorNode.parentNode;\r\n\r\n }\r\n\r\n /** Already founded, without loop */\r\n if (anchorNode.contentEditable == 'true') {\r\n\r\n flag = true;\r\n\r\n }\r\n\r\n while (anchorNode.contentEditable != 'true') {\r\n\r\n anchorNode = anchorNode.parentNode;\r\n\r\n if (anchorNode.contentEditable == 'true') {\r\n\r\n flag = true;\r\n\r\n }\r\n\r\n if (anchorNode == document.body) {\r\n\r\n break;\r\n\r\n }\r\n\r\n }\r\n\r\n /** If editable element founded, flag is \"TRUE\", Therefore we return \"FALSE\" */\r\n editor.content.editorAreaHightlighted = flag ? false : true;\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Toolbar button click handler\r\n * @param this - cursor to the button\r\n */\r\n callbacks.toolbarButtonClicked = function (event) {\r\n\r\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();\r\n\r\n };\r\n\r\n /** Show or Hide toolbox when plus button is clicked */\r\n callbacks.plusButtonClicked = function () {\r\n\r\n if (!editor.nodes.toolbox.classList.contains('opened')) {\r\n\r\n editor.toolbar.toolbox.open();\r\n\r\n } else {\r\n\r\n editor.toolbar.toolbox.close();\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Block handlers for KeyDown events\r\n */\r\n callbacks.blockKeydown = function (event) {\r\n\r\n let block = this; // event.target input\r\n\r\n switch (event.keyCode) {\r\n\r\n case editor.core.keys.DOWN:\r\n case editor.core.keys.RIGHT:\r\n editor.callback.blockRightOrDownArrowPressed();\r\n break;\r\n\r\n case editor.core.keys.BACKSPACE:\r\n editor.callback.backspacePressed(block, event);\r\n break;\r\n\r\n case editor.core.keys.UP:\r\n case editor.core.keys.LEFT:\r\n editor.callback.blockLeftOrUpArrowPressed();\r\n break;\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * RIGHT or DOWN keydowns on block\r\n */\r\n callbacks.blockRightOrDownArrowPressed = function () {\r\n\r\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) {\r\n\r\n return false;\r\n\r\n }\r\n\r\n /** Looking for closest (parent) contentEditable element of focused node */\r\n while (focusedNode.contentEditable != 'true') {\r\n\r\n focusedNodeHolder = focusedNode.parentNode;\r\n focusedNode = focusedNodeHolder;\r\n\r\n }\r\n\r\n /** Input index in DOM level */\r\n var editableElementIndex = 0;\r\n\r\n while (focusedNode != inputs[editableElementIndex]) {\r\n\r\n editableElementIndex ++;\r\n\r\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) {\r\n\r\n editor.caret.setToNextBlock(editableElementIndex);\r\n return;\r\n\r\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)) {\r\n\r\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length);\r\n\r\n } else {\r\n\r\n deepestTextnode = lastChild;\r\n\r\n }\r\n\r\n caretInLastChild = selection.anchorNode == deepestTextnode;\r\n caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset;\r\n\r\n if ( !caretInLastChild || !caretAtTheEndOfText ) {\r\n\r\n editor.core.log('arrow [down|right] : caret does not reached the end');\r\n return false;\r\n\r\n }\r\n\r\n editor.caret.setToNextBlock(editableElementIndex);\r\n\r\n };\r\n\r\n /**\r\n * LEFT or UP keydowns on block\r\n */\r\n callbacks.blockLeftOrUpArrowPressed = function () {\r\n\r\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) {\r\n\r\n return false;\r\n\r\n }\r\n\r\n /**\r\n * LEFT or UP not at the beginning\r\n */\r\n if ( selection.anchorOffset !== 0) {\r\n\r\n return false;\r\n\r\n }\r\n\r\n /** Looking for parent contentEditable block */\r\n while (focusedNode.contentEditable != 'true') {\r\n\r\n focusedNodeHolder = focusedNode.parentNode;\r\n focusedNode = focusedNodeHolder;\r\n\r\n }\r\n\r\n /** Input index in DOM level */\r\n var editableElementIndex = 0;\r\n\r\n while (focusedNode != inputs[editableElementIndex]) {\r\n\r\n editableElementIndex ++;\r\n\r\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) {\r\n\r\n editor.caret.setToPreviousBlock(editableElementIndex);\r\n return;\r\n\r\n }\r\n\r\n firstChild = focusedNode.childNodes[0];\r\n\r\n if (editor.core.isDomNode(firstChild)) {\r\n\r\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0);\r\n\r\n } else {\r\n\r\n deepestTextnode = firstChild;\r\n\r\n }\r\n\r\n caretInFirstChild = selection.anchorNode == deepestTextnode;\r\n caretAtTheBeginning = selection.anchorOffset === 0;\r\n\r\n if ( caretInFirstChild && caretAtTheBeginning ) {\r\n\r\n editor.caret.setToPreviousBlock(editableElementIndex);\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Callback for enter key pressing in first-level block area\r\n * @param {Event} event\r\n */\r\n callbacks.enterPressedOnBlock = function () {\r\n\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 }, true );\r\n\r\n editor.toolbar.move();\r\n editor.toolbar.open();\r\n\r\n };\r\n\r\n callbacks.backspacePressed = function (block, event) {\r\n\r\n var currentInputIndex = editor.caret.getCurrentInputIndex(),\r\n range,\r\n selectionLength,\r\n firstLevelBlocksCount;\r\n\r\n if (block.textContent.trim()) {\r\n\r\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]) {\r\n\r\n editor.content.mergeBlocks(currentInputIndex);\r\n\r\n } else {\r\n\r\n return;\r\n\r\n }\r\n\r\n }\r\n\r\n if (!selectionLength) {\r\n\r\n block.remove();\r\n\r\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) {\r\n\r\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 () {\r\n\r\n editor.caret.setToPreviousBlock(1);\r\n\r\n }, 10);\r\n\r\n } else {\r\n\r\n if (editor.caret.inputIndex !== 0) {\r\n\r\n /** Target block is not first */\r\n editor.caret.setToPreviousBlock(editor.caret.inputIndex);\r\n\r\n } else {\r\n\r\n /** If we try to delete first block */\r\n editor.caret.setToNextBlock(editor.caret.inputIndex);\r\n\r\n }\r\n\r\n }\r\n\r\n editor.toolbar.move();\r\n\r\n if (!editor.toolbar.opened) {\r\n\r\n editor.toolbar.open();\r\n\r\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();\r\n\r\n };\r\n\r\n /**\r\n * This method is used to observe pasted dirty data.\r\n *\r\n * Mutation handlers send to separate observers each mutation (added, changed and so on), which will be\r\n * passed from handler that sanitizes and replaces data.\r\n *\r\n * Probably won't be used\r\n *\r\n * @deprecated\r\n *\r\n * @param event\r\n * @private\r\n */\r\n callbacks._blockPasteCallback = function () {\r\n\r\n var currentInputIndex = editor.caret.getCurrentInputIndex();\r\n\r\n /**\r\n * create an observer instance\r\n */\r\n var observer = new MutationObserver(editor.callback.handleMutationsOnPaste);\r\n\r\n /**\r\n * configuration of the observer:\r\n */\r\n var config = {\r\n attributes: true,\r\n childList: false,\r\n characterData: false,\r\n subtree : true\r\n };\r\n\r\n // pass in the target node, as well as the observer options\r\n observer.observe(editor.state.inputs[currentInputIndex], config);\r\n\r\n };\r\n\r\n /**\r\n * This method prevents default behaviour.\r\n *\r\n * 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 * @param event\r\n */\r\n callbacks.blockPasteCallback = function (event) {\r\n\r\n /** Prevent default behaviour */\r\n event.preventDefault();\r\n\r\n var editableParent = editor.content.getEditableParent(event.target),\r\n firstLevelBlock = editor.content.getFirstLevelBlock(event.target);\r\n\r\n /** Allow paste when event target placed in Editable element */\r\n if (!editableParent) {\r\n\r\n return;\r\n\r\n }\r\n\r\n /** get html pasted data - dirty data */\r\n var data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain');\r\n\r\n /** Temporary DIV that is used to work with childs as arrays item */\r\n var div = editor.draw.node('DIV', '', {}),\r\n cleaner = new editor.sanitizer.init(editor.sanitizer.Config.BASIC),\r\n cleanData,\r\n fragment;\r\n\r\n /** Create fragment, that we paste to range after proccesing */\r\n fragment = document.createDocumentFragment();\r\n\r\n cleanData = cleaner.clean(data);\r\n\r\n div.innerHTML = cleanData;\r\n\r\n var node, lastNode;\r\n\r\n /**\r\n * and fill in fragment\r\n */\r\n while (( node = div.firstChild) ) {\r\n\r\n lastNode = fragment.appendChild(node);\r\n\r\n }\r\n\r\n\r\n if (editor.tools[firstLevelBlock.dataset.tool].allowRenderOnPaste) {\r\n\r\n if (editor.paste.pasted(event)) return;\r\n\r\n }\r\n\r\n /**\r\n * work with selection and range\r\n */\r\n var selection, range;\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(fragment);\r\n\r\n /** Preserve the selection */\r\n if (lastNode) {\r\n\r\n range = range.cloneRange();\r\n range.setStartAfter(lastNode);\r\n range.collapse(true);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n\r\n }\r\n\r\n };\r\n\r\n /**\r\n * Sends all mutations to paste handler\r\n */\r\n callbacks.handleMutationsOnPaste = function (mutations) {\r\n\r\n var self = this;\r\n\r\n /**\r\n * Calling function with context of this function.\r\n * Also, we should sanitize pasted or changed data one time and ignore\r\n * changings which makes sanitize method.\r\n * For that, we need to send Context, MutationObserver.__proto__ that contains\r\n * observer disconnect method.\r\n */\r\n mutations.forEach(function (mutation) {\r\n\r\n editor.content.paste.call(self, mutation);\r\n\r\n });\r\n\r\n };\r\n\r\n /**\r\n * Clicks on block settings button\r\n */\r\n callbacks.showSettingsButtonClicked = function () {\r\n\r\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();\r\n\r\n };\r\n\r\n return callbacks;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/callbacks.js","/**\r\n * Codex Editor Draw module\r\n *\r\n * @author Codex Team\r\n * @version 1.0.\r\n */\r\n\r\nmodule.exports = (function (draw) {\r\n\r\n /**\r\n * Base editor wrapper\r\n */\r\n draw.wrapper = function () {\r\n\r\n var wrapper = document.createElement('div');\r\n\r\n wrapper.className += 'codex-editor';\r\n\r\n return wrapper;\r\n\r\n };\r\n\r\n /**\r\n * Content-editable holder\r\n */\r\n draw.redactor = function () {\r\n\r\n var redactor = document.createElement('div');\r\n\r\n redactor.className += 'ce-redactor';\r\n\r\n return redactor;\r\n\r\n };\r\n\r\n draw.ceBlock = function () {\r\n\r\n var block = document.createElement('DIV');\r\n\r\n block.className += 'ce_block';\r\n\r\n return block;\r\n\r\n };\r\n\r\n /**\r\n * Empty toolbar with toggler\r\n */\r\n draw.toolbar = function () {\r\n\r\n var bar = document.createElement('div');\r\n\r\n bar.className += 'ce-toolbar';\r\n\r\n return bar;\r\n\r\n };\r\n\r\n draw.toolbarContent = function () {\r\n\r\n var wrapper = document.createElement('DIV');\r\n\r\n wrapper.classList.add('ce-toolbar__content');\r\n\r\n return wrapper;\r\n\r\n };\r\n\r\n /**\r\n * Inline toolbar\r\n */\r\n draw.inlineToolbar = function () {\r\n\r\n var bar = document.createElement('DIV');\r\n\r\n bar.className += 'ce-toolbar-inline';\r\n\r\n return bar;\r\n\r\n };\r\n\r\n /**\r\n * Wrapper for inline toobar buttons\r\n */\r\n draw.inlineToolbarButtons = function () {\r\n\r\n var wrapper = document.createElement('DIV');\r\n\r\n wrapper.className += 'ce-toolbar-inline__buttons';\r\n\r\n return wrapper;\r\n\r\n };\r\n\r\n /**\r\n * For some actions\r\n */\r\n draw.inlineToolbarActions = function () {\r\n\r\n var wrapper = document.createElement('DIV');\r\n\r\n wrapper.className += 'ce-toolbar-inline__actions';\r\n\r\n return wrapper;\r\n\r\n };\r\n\r\n draw.inputForLink = function () {\r\n\r\n var input = document.createElement('INPUT');\r\n\r\n input.type = 'input';\r\n input.className += 'inputForLink';\r\n input.placeholder = 'Вставьте ссылку ...';\r\n input.setAttribute('form', 'defaultForm');\r\n\r\n input.setAttribute('autofocus', 'autofocus');\r\n\r\n return input;\r\n\r\n };\r\n\r\n /**\r\n * @todo Desc\r\n */\r\n draw.blockButtons = function () {\r\n\r\n var block = document.createElement('div');\r\n\r\n block.className += 'ce-toolbar__actions';\r\n\r\n return block;\r\n\r\n };\r\n\r\n /**\r\n * Block settings panel\r\n */\r\n draw.blockSettings = function () {\r\n\r\n var settings = document.createElement('div');\r\n\r\n settings.className += 'ce-settings';\r\n\r\n return settings;\r\n\r\n };\r\n\r\n draw.defaultSettings = function () {\r\n\r\n var div = document.createElement('div');\r\n\r\n div.classList.add('ce-settings_default');\r\n\r\n return div;\r\n\r\n };\r\n\r\n draw.pluginsSettings = function () {\r\n\r\n var div = document.createElement('div');\r\n\r\n div.classList.add('ce-settings_plugin');\r\n\r\n return div;\r\n\r\n };\r\n\r\n draw.plusButton = function () {\r\n\r\n var button = document.createElement('span');\r\n\r\n button.className = 'ce-toolbar__plus';\r\n // button.innerHTML = '<i class=\"ce-icon-plus\"></i>';\r\n\r\n return button;\r\n\r\n };\r\n\r\n /**\r\n * Settings button in toolbar\r\n */\r\n draw.settingsButton = function () {\r\n\r\n var toggler = document.createElement('span');\r\n\r\n toggler.className = 'ce-toolbar__settings-btn';\r\n\r\n /** Toggler button*/\r\n toggler.innerHTML = '<i class=\"ce-icon-cog\"></i>';\r\n\r\n return toggler;\r\n\r\n };\r\n\r\n /**\r\n * Redactor tools wrapper\r\n */\r\n\r\n draw.toolbox = function () {\r\n\r\n var wrapper = document.createElement('div');\r\n\r\n wrapper.className = 'ce-toolbar__tools';\r\n\r\n return wrapper;\r\n\r\n };\r\n\r\n /**\r\n * @protected\r\n *\r\n * Draws tool buttons for toolbox\r\n *\r\n * @param {String} type\r\n * @param {String} classname\r\n * @returns {Element}\r\n */\r\n draw.toolbarButton = function (type, classname) {\r\n\r\n var button = document.createElement('li'),\r\n toolIcon = document.createElement('i'),\r\n toolTitle = document.createElement('span');\r\n\r\n button.dataset.type = type;\r\n button.setAttribute('title', type);\r\n\r\n toolIcon.classList.add(classname);\r\n toolTitle.classList.add('ce_toolbar_tools--title');\r\n\r\n\r\n button.appendChild(toolIcon);\r\n button.appendChild(toolTitle);\r\n\r\n return button;\r\n\r\n };\r\n\r\n /**\r\n * @protected\r\n *\r\n * Draws tools for inline toolbar\r\n *\r\n * @param {String} type\r\n * @param {String} classname\r\n */\r\n draw.toolbarButtonInline = function (type, classname) {\r\n\r\n var button = document.createElement('BUTTON'),\r\n toolIcon = document.createElement('I');\r\n\r\n button.type = 'button';\r\n button.dataset.type = type;\r\n toolIcon.classList.add(classname);\r\n\r\n button.appendChild(toolIcon);\r\n\r\n return button;\r\n\r\n };\r\n\r\n /**\r\n * Redactor block\r\n */\r\n draw.block = function (tagName, content) {\r\n\r\n var node = document.createElement(tagName);\r\n\r\n node.innerHTML = content || '';\r\n\r\n return node;\r\n\r\n };\r\n\r\n /**\r\n * Creates Node with passed tagName and className\r\n * @param {string} tagName\r\n * @param {string} className\r\n * @param {object} properties - allow to assign properties\r\n */\r\n draw.node = function ( tagName, className, properties ) {\r\n\r\n var el = document.createElement( tagName );\r\n\r\n if ( className ) el.className = className;\r\n\r\n if ( properties ) {\r\n\r\n for (var name in properties) {\r\n\r\n el[name] = properties[name];\r\n\r\n }\r\n\r\n }\r\n\r\n return el;\r\n\r\n };\r\n\r\n /**\r\n * Unavailable plugin block\r\n */\r\n draw.unavailableBlock = function () {\r\n\r\n var wrapper = document.createElement('DIV');\r\n\r\n wrapper.classList.add('cdx-unavailable-block');\r\n\r\n return wrapper;\r\n\r\n };\r\n\r\n return draw;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/draw.js","/**\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) {\r\n\r\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) {\r\n\r\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 ) {\r\n\r\n nodeToSet = el;\r\n\r\n } else {\r\n\r\n nodeToSet = childs[index];\r\n\r\n }\r\n\r\n /** If Element is INPUT */\r\n if (el.tagName == 'INPUT') {\r\n\r\n el.focus();\r\n return;\r\n\r\n }\r\n\r\n if (editor.core.isDomNode(nodeToSet)) {\r\n\r\n nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);\r\n\r\n }\r\n\r\n var range = document.createRange(),\r\n selection = window.getSelection();\r\n\r\n window.setTimeout(function () {\r\n\r\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();\r\n\r\n }, 20);\r\n\r\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 () {\r\n\r\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) {\r\n\r\n return;\r\n\r\n }\r\n\r\n /** Looking for parent contentEditable block */\r\n while (focusedNode.contentEditable != 'true') {\r\n\r\n focusedNodeHolder = focusedNode.parentNode;\r\n focusedNode = focusedNodeHolder;\r\n\r\n }\r\n\r\n /** Input index in DOM level */\r\n var editableElementIndex = 0;\r\n\r\n while (focusedNode != inputs[editableElementIndex]) {\r\n\r\n editableElementIndex ++;\r\n\r\n }\r\n\r\n caret.inputIndex = editableElementIndex;\r\n\r\n };\r\n\r\n /**\r\n * Returns current input index (caret object)\r\n */\r\n caret.getCurrentInputIndex = function () {\r\n\r\n return caret.inputIndex;\r\n\r\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) {\r\n\r\n var inputs = editor.state.inputs,\r\n nextInput = inputs[index + 1];\r\n\r\n if (!nextInput) {\r\n\r\n editor.core.log('We are reached the end');\r\n return;\r\n\r\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) {\r\n\r\n var emptyTextElement = document.createTextNode('');\r\n\r\n nextInput.appendChild(emptyTextElement);\r\n\r\n }\r\n\r\n editor.caret.inputIndex = index + 1;\r\n editor.caret.set(nextInput, 0, 0);\r\n editor.content.workingNodeChanged(nextInput);\r\n\r\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) {\r\n\r\n var inputs = editor.state.inputs,\r\n targetInput = inputs[index];\r\n\r\n if ( !targetInput ) {\r\n\r\n return;\r\n\r\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) {\r\n\r\n var emptyTextElement = document.createTextNode('');\r\n\r\n targetInput.appendChild(emptyTextElement);\r\n\r\n }\r\n\r\n editor.caret.inputIndex = index;\r\n editor.caret.set(targetInput, 0, 0);\r\n editor.content.workingNodeChanged(targetInput);\r\n\r\n };\r\n\r\n /**\r\n * @param {int} index - index of input\r\n */\r\n caret.setToPreviousBlock = function (index) {\r\n\r\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) {\r\n\r\n editor.core.log('We are reached first node');\r\n return;\r\n\r\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) {\r\n\r\n emptyTextElement = document.createTextNode('');\r\n previousInput.appendChild(emptyTextElement);\r\n\r\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]);\r\n\r\n };\r\n\r\n caret.position = {\r\n\r\n atStart : function () {\r\n\r\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)) {\r\n\r\n anchorNode = anchorNode.parentNode;\r\n\r\n }\r\n\r\n var isFirstNode = anchorNode === pluginsRender.childNodes[0],\r\n isOffsetZero = anchorOffset === 0;\r\n\r\n return isFirstNode && isOffsetZero;\r\n\r\n },\r\n\r\n atTheEnd : function () {\r\n\r\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;\r\n\r\n }\r\n };\r\n\r\n return caret;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/caret.js","/**\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) {\r\n\r\n let editor = codex.editor;\r\n\r\n var queue = [];\r\n\r\n var addToQueue = function (settings) {\r\n\r\n queue.push(settings);\r\n\r\n var index = 0;\r\n\r\n while ( index < queue.length && queue.length > 5) {\r\n\r\n if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\r\n\r\n index++;\r\n continue;\r\n\r\n }\r\n\r\n queue[index].close();\r\n queue.splice(index, 1);\r\n\r\n }\r\n\r\n };\r\n\r\n notifications.createHolder = function () {\r\n\r\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;\r\n\r\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) {\r\n\r\n editor.notifications.notification({message: 'This action is not available currently', type: event.type});\r\n\r\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) {\r\n\r\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 () {\r\n\r\n close();\r\n\r\n if (typeof confirm !== 'function' ) {\r\n\r\n return;\r\n\r\n }\r\n\r\n if (type == 'prompt') {\r\n\r\n confirm(inputField.value);\r\n return;\r\n\r\n }\r\n\r\n confirm();\r\n\r\n };\r\n\r\n var cancelHandler = function () {\r\n\r\n close();\r\n\r\n if (typeof cancel !== 'function' ) {\r\n\r\n return;\r\n\r\n }\r\n\r\n cancel();\r\n\r\n };\r\n\r\n\r\n /** Public methods */\r\n function create(settings) {\r\n\r\n if (!(settings && settings.message)) {\r\n\r\n editor.core.log('Can\\'t create notification. Message is missed');\r\n return;\r\n\r\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') {\r\n\r\n wrapper.appendChild(input);\r\n\r\n }\r\n\r\n wrapper.appendChild(okBtn);\r\n\r\n if (settings.type == 'prompt' || settings.type == 'confirm') {\r\n\r\n wrapper.appendChild(cancelBtn);\r\n\r\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') {\r\n\r\n window.setTimeout(close, settings.time);\r\n\r\n }\r\n\r\n };\r\n\r\n function send() {\r\n\r\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 () {\r\n\r\n editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\r\n\r\n }, 100);\r\n\r\n addToQueue({type: type, close: close});\r\n\r\n };\r\n\r\n function close() {\r\n\r\n notification.remove();\r\n\r\n };\r\n\r\n\r\n if (constructorSettings) {\r\n\r\n create(constructorSettings);\r\n send();\r\n\r\n }\r\n\r\n return {\r\n create: create,\r\n send: send,\r\n close: close\r\n };\r\n\r\n };\r\n\r\n notifications.clear = function () {\r\n\r\n editor.nodes.notifications.innerHTML = '';\r\n queue = [];\r\n\r\n };\r\n\r\n return notifications;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/notifications.js","/**\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) {\r\n\r\n let editor = codex.editor;\r\n\r\n /** inserting text */\r\n parser.insertPastedContent = function (blockType, tag) {\r\n\r\n editor.content.insertBlock({\r\n type : blockType.type,\r\n block : blockType.render({\r\n text : tag.innerHTML\r\n })\r\n });\r\n\r\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) {\r\n\r\n return node.nodeType == editor.core.nodeTypes.TAG &&\r\n node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\r\n\r\n };\r\n\r\n return parser;\r\n\r\n})({});\r\n\n\n\n// WEBPACK FOOTER //\n// ./modules/parser.js","/**\r\n * Codex Sanitizer\r\n */\r\n\r\nmodule.exports = (function (sanitizer) {\r\n\r\n var janitor = require('html-janitor');\r\n\r\n /**\r\n * Basic config\r\n */\r\n var Config = {\r\n\r\n BASIC : {\r\n\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 i: {},\r\n b: {},\r\n strong: {},\r\n em: {},\r\n span: {}\r\n }\r\n }\r\n };\r\n\r\n sanitizer.Config = Config;\r\n\r\n sanitizer.init = janitor;\r\n\r\n return sanitizer;\r\n\r\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/sanitizer.js","(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. <li><p>...); 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\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/html-janitor/src/html-janitor.js\n// module id = 18\n// module chunks = 0","/**\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) {\r\n\r\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) {\r\n\r\n anchors.currentNode = currentBlock;\r\n anchors.input.value = anchors.currentNode.dataset.anchor || '';\r\n\r\n };\r\n\r\n anchors.anchorChanged = function (e) {\r\n\r\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() !== '') {\r\n\r\n anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\r\n\r\n } else {\r\n\r\n anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);\r\n\r\n }\r\n\r\n };\r\n\r\n anchors.keyDownOnAnchorInput = function (e) {\r\n\r\n if (e.keyCode == editor.core.keys.ENTER) {\r\n\r\n e.preventDefault();\r\n e.stopPropagation();\r\n\r\n e.target.blur();\r\n editor.toolbar.settings.close();\r\n\r\n }\r\n\r\n };\r\n\r\n anchors.keyUpOnAnchorInput = function (e) {\r\n\r\n if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {\r\n\r\n e.stopPropagation();\r\n\r\n }\r\n\r\n };\r\n\r\n anchors.rusToTranslit = function (string) {\r\n\r\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++) {\r\n\r\n string = string.split(ru[i]).join(en[i]);\r\n string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());\r\n\r\n }\r\n\r\n string = string.replace(/[^0-9a-zA-Z_]+/g, '-');\r\n\r\n return string;\r\n\r\n };\r\n\r\n return anchors;\r\n\r\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/anchors.js","/**\r\n * Codex Editor Listeners module\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\n/**\r\n * Module-decorator for event listeners assignment\r\n */\r\nmodule.exports = function (listeners) {\r\n\r\n var allListeners = [];\r\n\r\n /**\r\n * Search methods\r\n *\r\n * byElement, byType and byHandler returns array of suitable listeners\r\n * one and all takes element, eventType, and handler and returns first (all) suitable listener\r\n *\r\n */\r\n listeners.search = function () {\r\n\r\n var byElement = function (element, context) {\r\n\r\n var listenersOnElement = [];\r\n\r\n context = context || allListeners;\r\n\r\n for (var i = 0; i < context.length; i++) {\r\n\r\n var listener = context[i];\r\n\r\n if (listener.element === element) {\r\n\r\n listenersOnElement.push(listener);\r\n\r\n }\r\n\r\n }\r\n\r\n return listenersOnElement;\r\n\r\n };\r\n\r\n var byType = function (eventType, context) {\r\n\r\n var listenersWithType = [];\r\n\r\n context = context || allListeners;\r\n\r\n for (var i = 0; i < context.length; i++) {\r\n\r\n var listener = context[i];\r\n\r\n if (listener.type === eventType) {\r\n\r\n listenersWithType.push(listener);\r\n\r\n }\r\n\r\n }\r\n\r\n return listenersWithType;\r\n\r\n };\r\n\r\n var byHandler = function (handler, context) {\r\n\r\n var listenersWithHandler = [];\r\n\r\n context = context || allListeners;\r\n\r\n for (var i = 0; i < context.length; i++) {\r\n\r\n var listener = context[i];\r\n\r\n if (listener.handler === handler) {\r\n\r\n listenersWithHandler.push(listener);\r\n\r\n }\r\n\r\n }\r\n\r\n return listenersWithHandler;\r\n\r\n };\r\n\r\n var one = function (element, eventType, handler) {\r\n\r\n var result = allListeners;\r\n\r\n if (element)\r\n result = byElement(element, result);\r\n\r\n if (eventType)\r\n result = byType(eventType, result);\r\n\r\n if (handler)\r\n result = byHandler(handler, result);\r\n\r\n return result[0];\r\n\r\n };\r\n\r\n var all = function (element, eventType, handler) {\r\n\r\n var result = allListeners;\r\n\r\n if (element)\r\n result = byElement(element, result);\r\n\r\n if (eventType)\r\n result = byType(eventType, result);\r\n\r\n if (handler)\r\n result = byHandler(handler, result);\r\n\r\n return result;\r\n\r\n };\r\n\r\n return {\r\n byElement : byElement,\r\n byType : byType,\r\n byHandler : byHandler,\r\n one : one,\r\n all : all\r\n };\r\n\r\n }();\r\n\r\n listeners.add = function (element, eventType, handler, isCapture) {\r\n\r\n element.addEventListener(eventType, handler, isCapture);\r\n\r\n var data = {\r\n element: element,\r\n type: eventType,\r\n handler: handler\r\n };\r\n\r\n var alreadyAddedListener = listeners.search.one(element, eventType, handler);\r\n\r\n if (!alreadyAddedListener) {\r\n\r\n allListeners.push(data);\r\n\r\n }\r\n\r\n };\r\n\r\n listeners.remove = function (element, eventType, handler) {\r\n\r\n element.removeEventListener(eventType, handler);\r\n\r\n var existingListeners = listeners.search.all(element, eventType, handler);\r\n\r\n for (var i = 0; i < existingListeners.length; i++) {\r\n\r\n var index = allListeners.indexOf(existingListeners[i]);\r\n\r\n if (index > 0) {\r\n\r\n allListeners.splice(index, 1);\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n listeners.removeAll = function () {\r\n\r\n allListeners.map(function (current) {\r\n\r\n listeners.remove(current.element, current.type, current.handler);\r\n\r\n });\r\n\r\n };\r\n\r\n listeners.get = function (element, eventType, handler) {\r\n\r\n return listeners.search.all(element, eventType, handler);\r\n\r\n };\r\n\r\n return listeners;\r\n\r\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/listeners.js","/**\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) {\r\n\r\n let editor = codex.editor;\r\n\r\n destroyer.removeNodes = function () {\r\n\r\n editor.nodes.wrapper.remove();\r\n editor.nodes.notifications.remove();\r\n\r\n };\r\n\r\n destroyer.destroyPlugins = function () {\r\n\r\n for (var tool in editor.tools) {\r\n\r\n if (typeof editor.tools[tool].destroy === 'function') {\r\n\r\n editor.tools[tool].destroy();\r\n\r\n }\r\n\r\n }\r\n\r\n };\r\n\r\n destroyer.destroyScripts = function () {\r\n\r\n var scripts = document.getElementsByTagName('SCRIPT');\r\n\r\n for (var i = 0; i < scripts.length; i++) {\r\n\r\n if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\r\n\r\n scripts[i].remove();\r\n i--;\r\n\r\n }\r\n\r\n }\r\n\r\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) {\r\n\r\n if (!settings || typeof settings !== 'object') {\r\n\r\n return;\r\n\r\n }\r\n\r\n if (settings.ui) {\r\n\r\n destroyer.removeNodes();\r\n editor.listeners.removeAll();\r\n\r\n }\r\n\r\n if (settings.scripts) {\r\n\r\n destroyer.destroyScripts();\r\n\r\n }\r\n\r\n if (settings.plugins) {\r\n\r\n destroyer.destroyPlugins();\r\n\r\n }\r\n\r\n if (settings.ui && settings.scripts && settings.core) {\r\n\r\n delete codex.editor;\r\n\r\n }\r\n\r\n };\r\n\r\n return destroyer;\r\n\r\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/destroyer.js","/**\r\n * Codex Editor Paste module\r\n *\r\n * @author Codex Team\r\n * @version 1.0\r\n */\r\n\r\nmodule.exports = function (paste) {\r\n\r\n let editor = codex.editor;\r\n\r\n var patterns = [];\r\n\r\n paste.prepare = function () {\r\n\r\n var tools = editor.tools;\r\n\r\n for (var tool in tools) {\r\n\r\n if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\r\n\r\n continue;\r\n\r\n }\r\n\r\n tools[tool].renderOnPastePatterns.map(function (pattern) {\r\n\r\n patterns.push(pattern);\r\n\r\n });\r\n\r\n }\r\n\r\n return Promise.resolve();\r\n\r\n };\r\n\r\n /**\r\n * Saves data\r\n * @param event\r\n */\r\n paste.pasted = function (event) {\r\n\r\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) {\r\n\r\n event.preventDefault();\r\n event.stopImmediatePropagation();\r\n\r\n }\r\n\r\n return result;\r\n\r\n };\r\n\r\n /**\r\n * Analizes pated string and calls necessary method\r\n */\r\n\r\n var analize = function (string) {\r\n\r\n var result = false,\r\n content = editor.content.currentNode,\r\n plugin = content.dataset.tool;\r\n\r\n patterns.map( function (pattern) {\r\n\r\n var execArray = pattern.regex.exec(string),\r\n match = execArray && execArray[0];\r\n\r\n if ( match && match === string.trim()) {\r\n\r\n /** current block is not empty */\r\n if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {\r\n\r\n pasteToNewBlock_();\r\n\r\n }\r\n\r\n pattern.callback(string, pattern);\r\n result = true;\r\n\r\n }\r\n\r\n });\r\n\r\n return result;\r\n\r\n };\r\n\r\n var pasteToNewBlock_ = function () {\r\n\r\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);\r\n\r\n };\r\n\r\n return paste;\r\n\r\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/paste.js"],"sourceRoot":""}