editor.js/codex-editor.js.map
Taly b9b07135f7 check for a coords or focusedNode is null (#255)
* check for a coords or focusedNode is null

* bump version
2018-05-25 17:49:46 +03:00

1 line
380 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 804711f99558afed9516","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/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","listeners","destroyer","paste","settings","holderId","initialBlockPlugin","nodes","holder","wrapper","inlineToolbar","buttons","actions","toolbox","plusButton","showSettingsButton","showTrashButton","blockSettings","pluginSettings","defaultSettings","toolbarButtons","redactor","state","jsonOutput","blocks","inputs","start","userSettings","prepare","then","makeBlocksFromData","saveInputs","catch","error","log","_typeof","Symbol","iterator","obj","constructor","prototype","Promise","resolve","reject","data","hideToolbar","placeholder","document","getElementById","undefined","Error","msg","type","arg","window","console","e","insertAfter","target","element","parentNode","insertBefore","nextSibling","nodeTypes","TAG","TEXT","COMMENT","DOCUMENT_FRAGMENT","keys","BACKSPACE","TAB","ENTER","SHIFT","CTRL","ALT","ESC","SPACE","LEFT","UP","DOWN","RIGHT","DELETE","META","isDomNode","el","nodeType","this","isEmpty","Object","length","ajax","url","encodedString","isFormData","prop","XMLHTTP","XMLHttpRequest","ActiveXObject","async","test","encodeURIComponent","withCredentials","responseContext","beforeSendResult","beforeSend","open","isFormData_","setRequestHeader","progress","upload","onprogress","bind","onreadystatechange","readyState","status","success","responseText","send","importScript","scriptPath","instanceName","script","createElement","defer","onload","onerror","src","head","appendChild","object","FormData","isNativeInput","nativeInputAreas","indexOf","tagName","isBlockEmpty","block","EXCEPTION_TAGS","nativeInputs","querySelectorAll","nativeInputsAreEmpty","textContentIsEmpty","textContent","trim","Array","forEach","input","value","includes","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","SETTINGS_ITEM","makeToolBar_","addTools_","makeInlineToolbar_","addInlineToolbarTools_","makeNotificationHolder_","bindEvents_","container","inlineToolbarButtons","inlineToolbarActions","blockButtons","makeToolbarSettings_","toolbarContent","makeToolbarContent_","settingsButton","makeRemoveBlockButton","pluginsSettings","createHolder","tool","toolName","toolButton","iconClassname","displayInToolbox","render","toolbarButton","bold","icon","command","italic","link","name","toolbarButtonInline","setInlineToolbarButtonBehaviour","add","globalKeydown","redactorKeyDown","globalKeyup","redactorClicked","plusButtonClicked","showSettingsButtonClicked","button","toolbarButtonClicked","addBlockHandlers","blockKeydown","blockPasteCallback","inline","show","map","current","addInitialBlock","initialBlock","initialBlockType","setAttribute","insertBlock","workingNodeChanged","event","toolClicked","currentRequest","arguments","node","fileSelected","clearInput","i","files","formData","multiple","append","selectAndUpload","args","accept","click","abort","items","appendBlocks","nodeSequence","index","appendNodeAtIndex","getNodeAsync","createBlockFromData","blockData","blocksList","position","toolData","unavailableBlock","innerHTML","dataset","inputPosition","stretched","isStretched","save","html","saveBlocks","childNodes","getBlockData","all","makeOutput","saveBlockData","validateBlockData","blockContent","pluginsContent","_ref","validate","result","savedData","filter","time","Date","currentNode","editorAreaHightlighted","sync","markBlock","classList","clearMark","remove","getFirstLevelBlock","body","contains","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","removeChild","lookingFromStart","getRange","selection","getSelection","getRangeAt","splitBlock","inputIndex","textBeforeCaret","textNodeBeforeCaret","textAfterCaret","textNodeAfterCaret","anchorNode","anchorNodeText","caretOffset","anchorOffset","currentBlock","substring","previousChilds","nextChilds","reachedCurrent","child","previousChildsLength","nextChildsLength","newNode","NEW_BLOCK_TYPE","mergeBlocks","targetInputIndex","targetInput","currentInputContent","isLastNode","allChecked","allSiblingsEmpty_","sibling","wrapTextWithParagraphs","htmlData","plainData","wrapPlainTextWithParagraphs","paragraph","blockTyped","newWrapper","firstLevelBlocks","cloneNode","plainText","split","join","getEditableParent","contentEditable","clear","load","articleData","currentContent","assign","concat","defaultToolbarHeight","defaultOffset","opened","toolType","makeSettings","close","toggle","hidePlusButton","newYCoordinate","offsetTop","style","transform","Math","floor","hideRemoveActions","setting","settingsBlock","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","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","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","openedOnBlock","leaf","currentTool","barButtons","nextToolIndex","toolToSelect","visibleTool","appendCallback","UNREPLACEBLE_TOOLS","workingNode","setToBlock","callbacks","enterKeyPressed_","tabKeyPressedOnRedactorsZone_","enterKeyPressedOnRedactorsZone_","escapeKeyPressedOnRedactorsZone_","defaultKeyPressedOnRedactorsZone_","arrowKeyPressed_","enterPressedOnBlock_","saveCurrentInputIndex","isEnterPressedOnToolbar","enableLineBreaks","stopPropagation","shiftKey","currentSelection","currentSelectedNode","caretAtTheEndOfText","atTheEnd","isTextNodeHasParentBetweenContenteditable","enterPressedOnBlock","islastNode","detectWhenClickedOnFirstLevelBlockArea_","firstLevelBlock","indexOfLastInput","inputIsEmpty","currentNodeType","isInitialType","flag","blockRightOrDownArrowPressed_","backspacePressed_","blockLeftOrUpArrowPressed_","focusedNodeHolder","focusedNode","editableElementIndex","lastChild","deepestTextnode","caretInLastChild","firstChild","caretInFirstChild","caretAtTheBeginning","setToPreviousBlock","selectionLength","endOffset","atStart","currentToolType","ceBlock","bar","div","toggler","classname","toolIcon","toolTitle","properties","focusedNodeIndex","nodeToSet","childs","nextInput","emptyTextElement","lastChildNode","lengthOfLastChildNode","previousInput","pluginsRender","isFirstNode","isOffsetZero","insertNode","lastNode","deleteContents","setStartAfter","queue","addToQueue","splice","errorThrown","errorMsg","notification","message","constructorSettings","create","okBtn","cancelBtn","okMsg","cancelMsg","confirmHandler","cancelHandler","confirm","cancel","inputField","insertPastedContent","isFirstLevelBlock","janitor","Config","CUSTOM","BASIC","tags","a","href","rel","init_","userCustomConfig","configuration","clean","dirtyString","customConfig","janitorInstance","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_RESULT__","root","factory","HTMLJanitor","tagDefinitions","validConfigValues","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","some","isNotTopContainer","isNestedBlockElement","isInvalid","keepNestedBlockElements","attributes","removeAttribute","previousElementSibling","nextElementSibling","allListeners","search","byElement","context","listenersOnElement","listener","byType","eventType","listenersWithType","byHandler","handler","listenersWithHandler","one","isCapture","addEventListener","alreadyAddedListener","removeEventListener","existingListeners","removeAll","get","removeNodes","destroyPlugins","destroy","destroyScripts","scripts","getElementsByTagName","patterns","renderOnPastePatterns","isArray","pattern","pasted","clipBoardData","clipboardData","getData","analize","string","execArray","regex","exec","match","pasteToNewBlock_","needsToHandlePasteEvent","cleanData","wrappedData","paragraphs","emulateUserAgentBehaviour","insertPastedParagraphs","editableParent","childElementCount","createDocumentFragment"],"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/**\n\t *\n\t * Codex Editor\n\t *\n\t * @author Codex Team\n\t */\n\t\n\tmodule.exports = function (editor) {\n\t\n\t 'use strict';\n\t\n\t editor.version = (\"1.7.9\");\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.listeners = __webpack_require__(19);\n\t editor.destroyer = __webpack_require__(20);\n\t editor.paste = __webpack_require__(21);\n\t };\n\t\n\t /**\n\t * @public\n\t * holds initial settings\n\t */\n\t editor.settings = {\n\t tools: ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n\t holderId: 'codex-editor',\n\t\n\t // Type of block showing on empty editor\n\t initialBlockPlugin: 'paragraph'\n\t };\n\t\n\t /**\n\t * public\n\t *\n\t * Static nodes\n\t */\n\t editor.nodes = {\n\t holder: 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 /**\n\t * @public\n\t *\n\t * Output state\n\t */\n\t editor.state = {\n\t jsonOutput: [],\n\t blocks: [],\n\t inputs: []\n\t };\n\t\n\t /**\n\t * @public\n\t * Editor plugins\n\t */\n\t editor.tools = {};\n\t\n\t /**\n\t * Initialization\n\t * @uses Promise cEditor.core.prepare\n\t * @param {Object} userSettings\n\t * @param {Array} userSettings.tools list of plugins\n\t * @param {String} userSettings.holderId Element's id to append editor\n\t *\n\t * Load user defined tools\n\t * Tools must contain this important objects :\n\t * @param {String} type - this is a type of plugin. It can be used as plugin name\n\t * @param {String} iconClassname - this a icon in toolbar\n\t * @param {Object} make - what should plugin do, when it is clicked\n\t * @param {Object} appendCallback - callback after clicking\n\t * @param {Element} settings - what settings does it have\n\t * @param {Object} render - plugin get JSON, and should return HTML\n\t * @param {Object} save - plugin gets HTML content, returns JSON\n\t * @param {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\n\t * @param {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\n\t *\n\t * @example\n\t * - type : 'header',\n\t * - iconClassname : 'ce-icon-header',\n\t * - make : headerTool.make,\n\t * - appendCallback : headerTool.appendCallback,\n\t * - settings : headerTool.makeSettings(),\n\t * - render : headerTool.render,\n\t * - save : headerTool.save,\n\t * - displayInToolbox : true,\n\t * - enableLineBreaks : false\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.prepare).then(editor.tools.prepare).then(editor.sanitizer.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/**\n\t * Codex Editor Core\n\t *\n\t * @author Codex Team\n\t * @version 1.1.3\n\t */\n\t\n\tmodule.exports = function (core) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * @public\n\t *\n\t * Editor preparing method\n\t * @return Promise\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.sanitizer) {\n\t\n\t editor.settings.sanitizer = userSettings.sanitizer;\n\t }\n\t\n\t editor.hideToolbar = userSettings.hideToolbar;\n\t\n\t editor.settings.placeholder = userSettings.placeholder || '';\n\t\n\t editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId);\n\t\n\t if (_typeof(editor.nodes.holder) === undefined || editor.nodes.holder === null) {\n\t\n\t reject(Error(\"Holder wasn't found by ID: #\" + userSettings.holderId));\n\t } else {\n\t\n\t resolve();\n\t }\n\t });\n\t };\n\t\n\t /**\n\t * Logging method\n\t * @param type = ['log', 'info', 'warn']\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 /**\n\t * @protected\n\t *\n\t * Helper for insert one element after another\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 /**\n\t * @const\n\t *\n\t * Readable DOM-node types map\n\t */\n\t core.nodeTypes = {\n\t TAG: 1,\n\t TEXT: 3,\n\t COMMENT: 8,\n\t DOCUMENT_FRAGMENT: 11\n\t };\n\t\n\t /**\n\t * @const\n\t * Readable keys map\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 /**\n\t * @protected\n\t *\n\t * Check object for DOM node\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 /**\n\t * Checks passed object for emptiness\n\t * @require ES5 - Object.keys\n\t * @param {object}\n\t */\n\t core.isEmpty = function (obj) {\n\t\n\t return Object.keys(obj).length === 0;\n\t };\n\t\n\t /**\n\t * Native Ajax\n\t * @param {String} settings.url - request URL\n\t * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks\n\t * @param {function} settings.success\n\t * @param {function} settings.progress\n\t */\n\t core.ajax = function (settings) {\n\t\n\t if (!settings || !settings.url) {\n\t\n\t return;\n\t }\n\t\n\t var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\n\t encodedString,\n\t isFormData,\n\t prop;\n\t\n\t settings.async = true;\n\t settings.type = settings.type || 'GET';\n\t settings.data = settings.data || '';\n\t settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8';\n\t\n\t if (settings.type == 'GET' && settings.data) {\n\t\n\t settings.url = /\\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data;\n\t } else {\n\t\n\t encodedString = '';\n\t for (prop in settings.data) {\n\t\n\t encodedString += prop + '=' + encodeURIComponent(settings.data[prop]) + '&';\n\t }\n\t }\n\t\n\t if (settings.withCredentials) {\n\t\n\t XMLHTTP.withCredentials = true;\n\t }\n\t\n\t /**\n\t * Value returned in beforeSend funtion will be passed as context to the other response callbacks\n\t * If beforeSend returns false, AJAX will be blocked\n\t */\n\t var responseContext = void 0,\n\t beforeSendResult = void 0;\n\t\n\t if (typeof settings.beforeSend === 'function') {\n\t\n\t beforeSendResult = settings.beforeSend.call();\n\t\n\t if (beforeSendResult === false) {\n\t\n\t return;\n\t }\n\t }\n\t\n\t XMLHTTP.open(settings.type, settings.url, settings.async);\n\t\n\t /**\n\t * If we send FormData, we need no content-type header\n\t */\n\t isFormData = isFormData_(settings.data);\n\t\n\t if (!isFormData) {\n\t\n\t if (settings.type !== 'POST') {\n\t\n\t XMLHTTP.setRequestHeader('Content-type', settings['content-type']);\n\t } else {\n\t\n\t XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n\t }\n\t }\n\t\n\t XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\t\n\t responseContext = beforeSendResult || XMLHTTP;\n\t\n\t if (typeof settings.progress === 'function') {\n\t\n\t XMLHTTP.upload.onprogress = settings.progress.bind(responseContext);\n\t }\n\t\n\t XMLHTTP.onreadystatechange = function () {\n\t\n\t if (XMLHTTP.readyState === 4) {\n\t\n\t if (XMLHTTP.status === 200) {\n\t\n\t if (typeof settings.success === 'function') {\n\t\n\t settings.success.call(responseContext, XMLHTTP.responseText);\n\t }\n\t } else {\n\t\n\t if (typeof settings.error === 'function') {\n\t\n\t settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status);\n\t }\n\t }\n\t }\n\t };\n\t\n\t if (isFormData) {\n\t\n\t // Sending FormData\n\t XMLHTTP.send(settings.data);\n\t } else {\n\t\n\t // POST requests\n\t XMLHTTP.send(encodedString);\n\t }\n\t\n\t return XMLHTTP;\n\t };\n\t\n\t /**\n\t * Appends script to head of document\n\t * @return Promise\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 /**\n\t * Function for checking is it FormData object to send.\n\t * @param {Object} object to check\n\t * @return boolean\n\t */\n\t var isFormData_ = function isFormData_(object) {\n\t\n\t return object instanceof FormData;\n\t };\n\t\n\t /**\n\t * Check block\n\t * @param target\n\t * @description Checks target is it native input\n\t */\n\t core.isNativeInput = function (target) {\n\t\n\t var nativeInputAreas = ['INPUT', 'TEXTAREA'];\n\t\n\t return nativeInputAreas.indexOf(target.tagName) != -1;\n\t };\n\t\n\t /**\n\t * Check if block is empty\n\t * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME\n\t *\n\t * @param block\n\t * @returns {boolean}\n\t */\n\t core.isBlockEmpty = function (block) {\n\t\n\t var EXCEPTION_TAGS = ['IMG', 'IFRAME'];\n\t\n\t var nativeInputs = block.querySelectorAll('textarea, input'),\n\t nativeInputsAreEmpty = true,\n\t textContentIsEmpty = !block.textContent.trim();\n\t\n\t Array.prototype.forEach.call(nativeInputs, function (input) {\n\t\n\t if (input.type == 'textarea' || input.type == 'text') {\n\t\n\t nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim();\n\t }\n\t });\n\t\n\t return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName);\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/**\n\t* Module working with plugins\n\t*/\n\tmodule.exports = function () {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Initialize plugins before using\n\t * Ex. Load scripts or call some internal methods\n\t * @return Promise\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 /**\n\t * Compose a sequence of plugins that requires preparation\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 /**\n\t * If no one passed plugins requires preparation, finish prepare() and go ahead\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 /**\n\t * @param {array} plugins - list of tools that requires preparation\n\t * @return {Promise} resolved while all plugins will be ready or failed\n\t */\n\t function waitAllPluginsPreparation_(plugins) {\n\t\n\t /**\n\t * @calls allPluginsProcessed__ when all plugins prepared or failed\n\t */\n\t return new Promise(function (allPluginsProcessed__) {\n\t\n\t /**\n\t * pluck each element from queue\n\t * First, send resolved Promise as previous value\n\t * Each plugins \"prepare\" method returns a Promise, that's why\n\t * reduce current element will not be able to continue while can't get\n\t * a resolved Promise\n\t *\n\t * If last plugin is \"prepared\" then go to the next stage of initialization\n\t */\n\t plugins.reduce(function (previousValue, plugin, iteration) {\n\t\n\t return previousValue.then(function () {\n\t\n\t /**\n\t * Wait till plugins prepared\n\t * @calls pluginIsReady__ when plugin is ready or failed\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/**\n\t * Codex Editor UI module\n\t *\n\t * @author Codex Team\n\t * @version 1.2.0\n\t */\n\t\n\tmodule.exports = function (ui) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Basic editor classnames\n\t */\n\t ui.className = {\n\t\n\t /**\n\t * @const {string} BLOCK_CLASSNAME - redactor blocks name\n\t */\n\t BLOCK_CLASSNAME: 'ce-block',\n\t\n\t /**\n\t * @const {String} wrapper for plugins content\n\t */\n\t BLOCK_CONTENT: 'ce-block__content',\n\t\n\t /**\n\t * @const {String} BLOCK_STRETCHED - makes block stretched\n\t */\n\t BLOCK_STRETCHED: 'ce-block--stretched',\n\t\n\t /**\n\t * @const {String} BLOCK_HIGHLIGHTED - adds background\n\t */\n\t BLOCK_HIGHLIGHTED: 'ce-block--focused',\n\t\n\t /**\n\t * @const {String} - for all default settings\n\t */\n\t SETTINGS_ITEM: 'ce-settings__item'\n\t\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Making main interface\n\t */\n\t ui.prepare = function () {\n\t\n\t return new Promise(function (resolve) {\n\t\n\t var wrapper = editor.draw.wrapper(),\n\t redactor = editor.draw.redactor(),\n\t toolbar = makeToolBar_();\n\t\n\t wrapper.appendChild(toolbar);\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.redactor = redactor;\n\t\n\t /** Append editor wrapper with redactor zone into holder */\n\t editor.nodes.holder.appendChild(wrapper);\n\t\n\t resolve();\n\t })\n\t\n\t /** Add toolbox tools */\n\t .then(addTools_)\n\t\n\t /** Make container for inline toolbar */\n\t .then(makeInlineToolbar_)\n\t\n\t /** Add inline toolbar tools */\n\t .then(addInlineToolbarTools_)\n\t\n\t /** Draw wrapper for notifications */\n\t .then(makeNotificationHolder_)\n\t\n\t /** Add eventlisteners to redactor elements */\n\t .then(bindEvents_).catch(function () {\n\t\n\t editor.core.log(\"Can't draw editor interface\");\n\t });\n\t };\n\t\n\t /**\n\t * @private\n\t * Draws inline toolbar zone\n\t */\n\t var makeInlineToolbar_ = function makeInlineToolbar_() {\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 var makeToolBar_ = function makeToolBar_() {\n\t\n\t var toolbar = editor.draw.toolbar(),\n\t blockButtons = makeToolbarSettings_(),\n\t toolbarContent = makeToolbarContent_();\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 /** Make toolbar global */\n\t editor.nodes.toolbar = toolbar;\n\t\n\t return toolbar;\n\t };\n\t\n\t var makeToolbarContent_ = function makeToolbarContent_() {\n\t\n\t var toolbarContent = editor.draw.toolbarContent(),\n\t toolbox = editor.draw.toolbox(),\n\t plusButton = editor.draw.plusButton();\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 /** Make Toolbox and plusButton global */\n\t editor.nodes.toolbox = toolbox;\n\t editor.nodes.plusButton = plusButton;\n\t\n\t return toolbarContent;\n\t };\n\t\n\t var makeToolbarSettings_ = function makeToolbarSettings_() {\n\t\n\t var blockSettings = editor.draw.blockSettings(),\n\t blockButtons = editor.draw.blockButtons(),\n\t defaultSettings = editor.draw.defaultSettings(),\n\t showSettingsButton = editor.draw.settingsButton(),\n\t showTrashButton = editor.toolbar.settings.makeRemoveBlockButton(),\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 /**\n\t * Make blocks buttons\n\t * This block contains settings button and remove block button\n\t */\n\t blockButtons.appendChild(showSettingsButton);\n\t blockButtons.appendChild(showTrashButton);\n\t blockButtons.appendChild(blockSettings);\n\t\n\t /** Make BlockSettings, PluginSettings, DefaultSettings global */\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 return blockButtons;\n\t };\n\t\n\t /** Draw notifications holder */\n\t var makeNotificationHolder_ = function makeNotificationHolder_() {\n\t\n\t /** Append block with notifications to the document */\n\t editor.nodes.notifications = editor.notifications.createHolder();\n\t };\n\t\n\t /**\n\t * @private\n\t * Append tools passed in editor.tools\n\t */\n\t var addTools_ = function addTools_() {\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 && tool.displayInToolbox) {\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\n\t var addInlineToolbarTools_ = function addInlineToolbarTools_() {\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 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 /**\n\t * Add callbacks to this buttons\n\t */\n\t editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);\n\t }\n\t };\n\t\n\t /**\n\t * @private\n\t * Bind editor UI events\n\t */\n\t var bindEvents_ = function bindEvents_() {\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 /**\n\t * Mouse click to radactor\n\t */\n\t editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false);\n\t\n\t /**\n\t * Clicks to the Plus button\n\t */\n\t editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n\t\n\t /**\n\t * Clicks to SETTINGS button in toolbar\n\t */\n\t editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, 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 /**\n\t * Block keydowns\n\t */\n\t editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n\t\n\t /**\n\t * Pasting content from another source\n\t * We have two type of sanitization\n\t * First - uses deep-first search algorithm to get sub nodes,\n\t * sanitizes whole Block_content and replaces cleared nodes\n\t * This method is deprecated\n\t * Method is used in editor.callback.blockPaste(event)\n\t *\n\t * Secont - uses Mutation observer.\n\t * Observer \"observe\" DOM changes and send changings to callback.\n\t * Callback gets changed node, not whole Block_content.\n\t * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n\t *\n\t * Method is used in editor.callback.blockPasteViaSanitize(event)\n\t *\n\t * @uses html-janitor\n\t * @example editor.callback.blockPasteViaSanitize(event), the second method.\n\t *\n\t */\n\t editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);\n\t\n\t /**\n\t * Show inline toolbar for selected text\n\t */\n\t editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\n\t editor.listeners.add(block, 'keyup', 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 editor.state.inputs = [];\n\t\n\t /** Save all inputs in global variable state */\n\t var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\n\t\n\t Array.prototype.map.call(inputs, function (current) {\n\t\n\t if (!current.type || current.type == 'text' || current.type == 'textarea') {\n\t\n\t editor.state.inputs.push(current);\n\t }\n\t });\n\t };\n\t\n\t /**\n\t * Adds first initial block on empty redactor\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', editor.settings.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/**\n\t *\n\t * Codex.Editor Transport Module\n\t *\n\t * @copyright 2017 Codex-Team\n\t * @version 1.2.0\n\t */\n\t\n\tmodule.exports = function (transport) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * @private {Object} current XmlHttpRequest instance\n\t */\n\t var currentRequest = null;\n\t\n\t /**\n\t * @type {null} | {DOMElement} input - keeps input element in memory\n\t */\n\t transport.input = null;\n\t\n\t /**\n\t * @property {Object} arguments - keep plugin settings and defined callbacks\n\t */\n\t transport.arguments = null;\n\t\n\t /**\n\t * Prepares input element where will be files\n\t */\n\t transport.prepare = function () {\n\t\n\t var input = editor.draw.node('INPUT', '', { type: 'file' });\n\t\n\t editor.listeners.add(input, 'change', editor.transport.fileSelected);\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 transport.input = null;\n\t\n\t /** Prepare new one */\n\t transport.prepare();\n\t };\n\t\n\t /**\n\t * Callback for file selection\n\t * @param {Event} event\n\t */\n\t transport.fileSelected = function () {\n\t\n\t var input = this,\n\t i,\n\t files = input.files,\n\t formData = new FormData();\n\t\n\t if (editor.transport.arguments.multiple === true) {\n\t\n\t for (i = 0; i < files.length; i++) {\n\t\n\t formData.append('files[]', files[i], files[i].name);\n\t }\n\t } else {\n\t\n\t formData.append('files', files[0], files[0].name);\n\t }\n\t\n\t currentRequest = editor.core.ajax({\n\t type: 'POST',\n\t data: formData,\n\t url: editor.transport.arguments.url,\n\t beforeSend: editor.transport.arguments.beforeSend,\n\t success: editor.transport.arguments.success,\n\t error: editor.transport.arguments.error,\n\t progress: editor.transport.arguments.progress\n\t });\n\t\n\t /** Clear input */\n\t transport.clearInput();\n\t };\n\t\n\t /**\n\t * Use plugin callbacks\n\t * @protected\n\t *\n\t * @param {Object} args - can have :\n\t * @param {String} args.url - fetch URL\n\t * @param {Function} args.beforeSend - function calls before sending ajax\n\t * @param {Function} args.success - success callback\n\t * @param {Function} args.error - on error handler\n\t * @param {Function} args.progress - xhr onprogress handler\n\t * @param {Boolean} args.multiple - allow select several files\n\t * @param {String} args.accept - adds accept attribute\n\t */\n\t transport.selectAndUpload = function (args) {\n\t\n\t transport.arguments = args;\n\t\n\t if (args.multiple === true) {\n\t\n\t transport.input.setAttribute('multiple', 'multiple');\n\t }\n\t\n\t if (args.accept) {\n\t\n\t transport.input.setAttribute('accept', args.accept);\n\t }\n\t\n\t transport.input.click();\n\t };\n\t\n\t transport.abort = function () {\n\t\n\t currentRequest.abort();\n\t\n\t currentRequest = null;\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/**\n\t * Codex Editor Renderer Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (renderer) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Asyncronously parses input JSON to redactor blocks\n\t */\n\t renderer.makeBlocksFromData = function () {\n\t\n\t /**\n\t * If redactor is empty, add first paragraph to start writing\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 /**\n\t * Parses JSON to blocks\n\t * @param {object} data\n\t * @return Primise -> nodeList\n\t */\n\t renderer.appendBlocks = function (data) {\n\t\n\t var blocks = data.items;\n\t\n\t /**\n\t * Sequence of one-by-one blocks appending\n\t * Uses to save blocks order after async-handler\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 /**\n\t * Append node at specified index\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 /**\n\t * second, compose editor-block from JSON object\n\t */\n\t .then(editor.renderer.createBlockFromData)\n\t\n\t /**\n\t * now insert block to redactor\n\t */\n\t .then(function (blockData) {\n\t\n\t /**\n\t * blockData has 'block', 'type' and 'stretched' information\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 /**\n\t * Asynchronously returns block data from blocksList by index\n\t * @return Promise to node\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 /**\n\t * Creates editor block by JSON-data\n\t *\n\t * @uses render method of each plugin\n\t *\n\t * @param {Object} toolData.tool\n\t * { header : {\n\t * text: '',\n\t * type: 'H3', ...\n\t * }\n\t * }\n\t * @param {Number} toolData.position - index in input-blocks array\n\t * @return {Object} with type and Element\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\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 /**\n\t * Saver will extract data from initial block data by position in array\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 };\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/**\n\t * Codex Editor Saver\n\t *\n\t * @author Codex Team\n\t * @version 1.1.0\n\t */\n\t\n\tmodule.exports = function (saver) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * @public\n\t * Save blocks\n\t */\n\t saver.save = 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 /** Clean jsonOutput state */\n\t editor.state.jsonOutput = [];\n\t\n\t return saveBlocks(editor.nodes.redactor.childNodes);\n\t };\n\t\n\t /**\n\t * @private\n\t * Save each block data\n\t *\n\t * @param blocks\n\t * @returns {Promise.<TResult>}\n\t */\n\t var saveBlocks = function saveBlocks(blocks) {\n\t\n\t var data = [];\n\t\n\t for (var index = 0; index < blocks.length; index++) {\n\t\n\t data.push(getBlockData(blocks[index]));\n\t }\n\t\n\t return Promise.all(data).then(makeOutput).catch(editor.core.log);\n\t };\n\t\n\t /** Save and validate block data */\n\t var getBlockData = function getBlockData(block) {\n\t\n\t return saveBlockData(block).then(validateBlockData).catch(editor.core.log);\n\t };\n\t\n\t /**\n\t * @private\n\t * Call block`s plugin save method and return saved data\n\t *\n\t * @param block\n\t * @returns {Object}\n\t */\n\t var saveBlockData = function saveBlockData(block) {\n\t\n\t var pluginName = block.dataset.tool;\n\t\n\t /** Check for plugin existence */\n\t if (!editor.tools[pluginName]) {\n\t\n\t editor.core.log('Plugin \\xAB' + pluginName + '\\xBB not found', 'error');\n\t return { data: null, pluginName: null };\n\t }\n\t\n\t /** Check for plugin having save method */\n\t if (typeof editor.tools[pluginName].save !== 'function') {\n\t\n\t editor.core.log('Plugin \\xAB' + pluginName + '\\xBB must have save method', 'error');\n\t return { data: null, pluginName: null };\n\t }\n\t\n\t /** Result saver */\n\t var blockContent = block.childNodes[0],\n\t pluginsContent = blockContent.childNodes[0],\n\t position = pluginsContent.dataset.inputPosition;\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 return Promise.resolve({ data: codex.editor.state.blocks.items[position].data, pluginName: pluginName });\n\t }\n\t\n\t return Promise.resolve(pluginsContent).then(editor.tools[pluginName].save).then(function (data) {\n\t return Object({ data: data, pluginName: pluginName });\n\t });\n\t };\n\t\n\t /**\n\t * Call plugin`s validate method. Return false if validation failed\n\t *\n\t * @param data\n\t * @param pluginName\n\t * @returns {Object|Boolean}\n\t */\n\t var validateBlockData = function validateBlockData(_ref) {\n\t var data = _ref.data,\n\t pluginName = _ref.pluginName;\n\t\n\t\n\t if (!data || !pluginName) {\n\t\n\t return false;\n\t }\n\t\n\t if (editor.tools[pluginName].validate) {\n\t\n\t var result = editor.tools[pluginName].validate(data);\n\t\n\t /**\n\t * Do not allow invalid data\n\t */\n\t if (!result) {\n\t\n\t return false;\n\t }\n\t }\n\t\n\t return { data: data, pluginName: pluginName };\n\t };\n\t\n\t /**\n\t * Compile article output\n\t *\n\t * @param savedData\n\t * @returns {{time: number, version, items: (*|Array)}}\n\t */\n\t var makeOutput = function makeOutput(savedData) {\n\t\n\t savedData = savedData.filter(function (blockData) {\n\t return blockData;\n\t });\n\t\n\t var items = savedData.map(function (blockData) {\n\t return Object({ type: blockData.pluginName, data: blockData.data });\n\t });\n\t\n\t editor.state.jsonOutput = items;\n\t\n\t return {\n\t id: editor.state.blocks.id || null,\n\t time: +new Date(),\n\t version: editor.version,\n\t items: items\n\t };\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/**\n\t * Codex Editor Content Module\n\t * Works with DOM\n\t *\n\t * @module Codex Editor content module\n\t *\n\t * @author Codex Team\n\t * @version 1.3.13\n\t *\n\t * @description Module works with Elements that have been appended to the main DOM\n\t */\n\t\n\tmodule.exports = function (content) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Links to current active block\n\t * @type {null | Element}\n\t */\n\t content.currentNode = null;\n\t\n\t /**\n\t * clicked in redactor area\n\t * @type {null | Boolean}\n\t */\n\t content.editorAreaHightlighted = null;\n\t\n\t /**\n\t * @deprecated\n\t * Synchronizes redactor with original textarea\n\t */\n\t content.sync = function () {\n\t\n\t editor.core.log('syncing...');\n\t\n\t /**\n\t * Save redactor content to editor.state\n\t */\n\t editor.state.html = editor.nodes.redactor.innerHTML;\n\t };\n\t\n\t /**\n\t * Appends background to the block\n\t *\n\t * @description add CSS class to highlight visually first-level block area\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 /**\n\t * Clear background\n\t *\n\t * @description clears styles that highlights block\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 /**\n\t * Finds first-level block\n\t *\n\t * @param {Element} node - selected or clicked in redactors area node\n\t * @protected\n\t *\n\t * @description looks for first-level block.\n\t * gets parent while node is not first-level\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 /**\n\t * Trigger this event when working node changed\n\t * @param {Element} targetNode - first-level of this node will be current\n\t * @protected\n\t *\n\t * @description If targetNode is first-level then we set it as current else we look for parents to find first-level\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 content.currentNode = content.getFirstLevelBlock(targetNode);\n\t };\n\t\n\t /**\n\t * Replaces one redactor block with another\n\t * @protected\n\t * @param {Element} targetBlock - block to replace. Mostly currentNode.\n\t * @param {Element} newBlock\n\t * @param {string} newBlockType - type of new block; we need to store it to data-attribute\n\t *\n\t * [!] Function does not saves old block content.\n\t * You can get it manually and pass with newBlock.innerHTML\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 /** Replacing */\n\t editor.nodes.redactor.replaceChild(newBlock, targetBlock);\n\t\n\t /**\n\t * Set new node as current\n\t */\n\t editor.content.workingNodeChanged(newBlock);\n\t\n\t /**\n\t * Add block handlers\n\t */\n\t editor.ui.addBlockHandlers(newBlock);\n\t\n\t /**\n\t * Save changes\n\t */\n\t editor.ui.saveInputs();\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Inserts new block to redactor\n\t * Wrapps block into a DIV with BLOCK_CLASSNAME class\n\t *\n\t * @param blockData {object}\n\t * @param blockData.block {Element} element with block content\n\t * @param blockData.type {string} block plugin\n\t * @param needPlaceCaret {bool} pass true to set caret in new block\n\t *\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 isStretched = blockData.stretched;\n\t\n\t var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched);\n\t\n\t if (workingBlock) {\n\t\n\t editor.core.insertAfter(workingBlock, newBlock);\n\t } else {\n\t\n\t /**\n\t * If redactor is empty, append as first child\n\t */\n\t editor.nodes.redactor.appendChild(newBlock);\n\t }\n\t\n\t /**\n\t * Block handler\n\t */\n\t editor.ui.addBlockHandlers(newBlock);\n\t\n\t /**\n\t * Set new node as current\n\t */\n\t editor.content.workingNodeChanged(newBlock);\n\t\n\t /**\n\t * Save changes\n\t */\n\t editor.ui.saveInputs();\n\t\n\t if (needPlaceCaret) {\n\t\n\t /**\n\t * If we don't know input index then we set default value -1\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 /**\n\t * Block is inserted, wait for new click that defined focusing on editors area\n\t * @type {boolean}\n\t */\n\t content.editorAreaHightlighted = false;\n\t };\n\t\n\t /**\n\t * Replaces blocks with saving content\n\t * @protected\n\t * @param {Element} noteToReplace\n\t * @param {Element} newNode\n\t * @param {Element} blockType\n\t */\n\t content.switchBlock = function (blockToReplace, newBlock, tool) {\n\t\n\t tool = tool || editor.content.currentNode.dataset.tool;\n\t var newBlockComposed = 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 /**\n\t * Iterates between child noted and looking for #text node on deepest level\n\t * @protected\n\t *\n\t * @param {Element} block - node where find\n\t * @param {int} postiton - starting postion\n\t * Example: childNodex.length to find from the end\n\t * or 0 to find from the start\n\t * @return {Text} block\n\t * @uses DFS\n\t */\n\t content.getDeepestTextNodeFromPosition = function (block, position) {\n\t\n\t /**\n\t * Clear Block from empty and useless spaces with trim.\n\t * Such nodes we should remove\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\n\t * decrease the quantity of childs.\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 /**\n\t * @private\n\t * @param {Element} block - current plugins render\n\t * @param {String} tool - plugins name\n\t * @param {Boolean} isStretched - make stretched block or not\n\t *\n\t * @description adds necessary information to wrap new created block by first-level holder\n\t */\n\t var composeNewBlock_ = function composeNewBlock_(block, tool, isStretched) {\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 return newBlock;\n\t };\n\t\n\t /**\n\t * Returns Range object of current selection\n\t * @protected\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 /**\n\t * Divides block in two blocks (after and before caret)\n\t *\n\t * @protected\n\t * @param {int} inputIndex - target input index\n\t *\n\t * @description splits current input content to the separate blocks\n\t * When enter is pressed among the words, that text will be splited.\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 /**\n\t * Append all childs founded before anchorNode\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 /**\n\t * Append text node which is after caret\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 /**\n\t * Make new paragraph with text after caret\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 /**\n\t * Merges two blocks — current and target\n\t * If target index is not exist, then previous will be as target\n\t *\n\t * @protected\n\t * @param {int} currentInputIndex\n\t * @param {int} targetInputIndex\n\t *\n\t * @description gets two inputs indexes and merges into one\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 /**\n\t * Iterates all right siblings and parents, which has right siblings\n\t * while it does not reached the first-level block\n\t *\n\t * @param {Element} node\n\t * @return {boolean}\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 /**\n\t * Проверяем родителей до тех пор, пока не найдем блок первого уровня\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 /**\n\t * Checks if all element right siblings is empty\n\t * @param node\n\t */\n\t var allSiblingsEmpty_ = function allSiblingsEmpty_(node) {\n\t\n\t /**\n\t * Нужно убедиться, что после пустого соседа ничего нет\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 /**\n\t * @public\n\t *\n\t * @param {string} htmlData - html content as string\n\t * @param {string} plainData - plain text\n\t * @return {string} - html content as string\n\t */\n\t content.wrapTextWithParagraphs = function (htmlData, plainData) {\n\t\n\t if (!htmlData.trim()) {\n\t\n\t return wrapPlainTextWithParagraphs(plainData);\n\t }\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 /**\n\t * Make HTML Element to Wrap Text\n\t * It allows us to work with input data as HTML content\n\t */\n\t wrapper.innerHTML = htmlData;\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 /**\n\t * If node is first-levet\n\t * we add this node to our new wrapper\n\t */\n\t if (blockTyped) {\n\t\n\t /**\n\t * If we had splitted inline nodes to paragraph before\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 /**\n\t * Splits strings on new line and wraps paragraphs with <p> tag\n\t * @param plainText\n\t * @returns {string}\n\t */\n\t var wrapPlainTextWithParagraphs = function wrapPlainTextWithParagraphs(plainText) {\n\t\n\t if (!plainText) return '';\n\t\n\t return '<p>' + plainText.split('\\n\\n').join('</p><p>') + '</p>';\n\t };\n\t\n\t /**\n\t * Finds closest Contenteditable parent from Element\n\t * @param {Element} node element looking from\n\t * @return {Element} node contenteditable\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 /**\n\t * Clear editors content\n\t *\n\t * @param {Boolean} all — if true, delete all article data (content, id, etc.)\n\t */\n\t content.clear = function (all) {\n\t\n\t editor.nodes.redactor.innerHTML = '';\n\t editor.content.sync();\n\t editor.ui.saveInputs();\n\t if (all) {\n\t\n\t editor.state.blocks = {};\n\t } else if (editor.state.blocks) {\n\t\n\t editor.state.blocks.items = [];\n\t }\n\t\n\t editor.content.currentNode = null;\n\t };\n\t\n\t /**\n\t *\n\t * Load new data to editor\n\t * If editor is not empty, just append articleData.items\n\t *\n\t * @param articleData.items\n\t */\n\t content.load = function (articleData) {\n\t\n\t var currentContent = Object.assign({}, editor.state.blocks);\n\t\n\t editor.content.clear();\n\t\n\t if (!Object.keys(currentContent).length) {\n\t\n\t editor.state.blocks = articleData;\n\t } else if (!currentContent.items) {\n\t\n\t currentContent.items = articleData.items;\n\t editor.state.blocks = currentContent;\n\t } else {\n\t\n\t currentContent.items = currentContent.items.concat(articleData.items);\n\t editor.state.blocks = currentContent;\n\t }\n\t\n\t editor.renderer.makeBlocksFromData();\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/**\n\t * Codex Editor toolbar module\n\t *\n\t * Contains:\n\t * - Inline toolbox\n\t * - Toolbox within plus button\n\t * - Settings section\n\t *\n\t * @author Codex Team\n\t * @version 1.0\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 /**\n\t * Margin between focused node and toolbar\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 /**\n\t * @protected\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 var toolType = editor.content.currentNode.dataset.tool;\n\t\n\t if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings) {\n\t\n\t editor.nodes.showSettingsButton.classList.add('hide');\n\t } else {\n\t\n\t editor.nodes.showSettingsButton.classList.remove('hide');\n\t }\n\t\n\t editor.nodes.toolbar.classList.add('opened');\n\t this.opened = true;\n\t };\n\t\n\t /**\n\t * @protected\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 /**\n\t * Moving toolbar to the specified node\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/**\n\t * Toolbar settings\n\t *\n\t * @version 1.0.5\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 /**\n\t * Append and open settings\n\t */\n\t settings.open = function (toolType) {\n\t\n\t /**\n\t * Append settings content\n\t * It's stored in tool.settings\n\t */\n\t if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings) {\n\t\n\t return;\n\t }\n\t\n\t /**\n\t * Draw settings block\n\t */\n\t var settingsBlock = editor.tools[toolType].makeSettings();\n\t\n\t editor.nodes.pluginSettings.appendChild(settingsBlock);\n\t\n\t /** Open settings block */\n\t editor.nodes.blockSettings.classList.add('opened');\n\t this.opened = true;\n\t };\n\t\n\t /**\n\t * Close and clear settings\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 /**\n\t * @param {string} toolType - plugin type\n\t */\n\t settings.toggle = function (toolType) {\n\t\n\t if (!this.opened) {\n\t\n\t this.open(toolType);\n\t } else {\n\t\n\t this.close();\n\t }\n\t };\n\t\n\t /**\n\t * Here we will draw buttons and add listeners to components\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 /**\n\t * If all blocks are removed\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/**\n\t * Inline toolbar\n\t *\n\t * Contains from tools:\n\t * Bold, Italic, Underline and Anchor\n\t *\n\t * @author Codex Team\n\t * @version 1.0\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 /**\n\t * saving selection that need for execCommand for styling\n\t *\n\t */\n\t inline.storedSelection = null;\n\t\n\t /**\n\t * @protected\n\t *\n\t * Open inline toobar\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 /**\n\t * tool allowed to open inline toolbar\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 /**\n\t * @protected\n\t *\n\t * Closes inline toolbar\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 /**\n\t * @private\n\t *\n\t * Moving toolbar\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 (!coords) {\n\t\n\t return;\n\t }\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 /**\n\t * @private\n\t *\n\t * Tool Clicked\n\t */\n\t\n\t inline.toolClicked = function (event, type) {\n\t\n\t /**\n\t * For simple tools we use default browser function\n\t * For more complicated tools, we should write our own behavior\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 /**\n\t * highlight buttons\n\t * after making some action\n\t */\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Saving wrappers offset in DOM\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 /**\n\t * @private\n\t *\n\t * Calculates offset of DOM element\n\t *\n\t * @param el\n\t * @returns {{top: number, left: number}}\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 /**\n\t * @private\n\t *\n\t * Calculates position of selected text\n\t * @returns {{x: number, y: number}}\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 /**\n\t * @private\n\t *\n\t * Returns selected text as String\n\t * @returns {string}\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 /**\n\t * Callback for keydowns in inline toolbar \"Insert link...\" input\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 /**\n\t * Preventing events that will be able to happen\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 /**\n\t * Changing stored selection. if we want to remove anchor from word\n\t * we should remove anchor from whole word, not only selected part.\n\t * The solution is than we get the length of current link\n\t * Change start position to - end of selection minus length of anchor\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 /**\n\t * focus to input\n\t * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\n\t * Prevents event after showing input and when we need to focus an input which is in unexisted form\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 /**\n\t * @private\n\t *\n\t * Sets URL\n\t *\n\t * @param {String} url - URL\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 /**\n\t * @private\n\t *\n\t * Saves selection\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 /**\n\t * @private\n\t *\n\t * Sets to previous selection (Range)\n\t *\n\t * @param {Element} containerEl - editable element where we restore range\n\t * @param {Object} savedSel - range basic information to restore\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 /**\n\t * @private\n\t *\n\t * Removes all ranges from window selection\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 /**\n\t * @private\n\t *\n\t * sets or removes hightlight\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 /**\n\t *\n\t * hightlight for anchors\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 /**\n\t * @private\n\t *\n\t * Mark button if text is already executed\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 /**\n\t * @private\n\t *\n\t * Removes hightlight\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/**\n\t * Codex Editor toolbox\n\t *\n\t * All tools be able to appended here\n\t *\n\t * @author Codex Team\n\t * @version 1.0\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 toolbox.openedOnBlock = null;\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 /** Add 'toolbar-opened' class for current block **/\n\t toolbox.openedOnBlock = editor.content.currentNode;\n\t toolbox.openedOnBlock.classList.add('toolbar-opened');\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 /** Remove 'toolbar-opened' class from current block **/\n\t if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened');\n\t toolbox.openedOnBlock = null;\n\t\n\t /** Makes toolbox disappear */\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 editor.toolbar.current = null;\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) % tools.length;\n\t visibleTool = tools[nextToolIndex];\n\t\n\t while (!editor.tools[visibleTool].displayInToolbox) {\n\t\n\t nextToolIndex = (nextToolIndex + 1) % tools.length;\n\t visibleTool = tools[nextToolIndex];\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 /**\n\t * Transforming selected node type into selected toolbar element type\n\t * @param {event} event\n\t */\n\t toolbox.toolClicked = function (event) {\n\t\n\t /**\n\t * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty\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 /**\n\t * Changing current Node\n\t */\n\t editor.content.workingNodeChanged();\n\t\n\t /**\n\t * Move toolbar when node is changed\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/**\n\t * @module Codex Editor Callbacks module\n\t * @description Module works with editor added Elements\n\t *\n\t * @author Codex Team\n\t * @version 1.4.0\n\t */\n\t\n\tmodule.exports = function (callbacks) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * used by UI module\n\t * @description Routes all keydowns on document\n\t * @param {Object} event\n\t */\n\t callbacks.globalKeydown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.ENTER:\n\t enterKeyPressed_(event);break;\n\t }\n\t };\n\t\n\t /**\n\t * used by UI module\n\t * @description Routes all keydowns on redactors area\n\t * @param {Object} event\n\t */\n\t callbacks.redactorKeyDown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.TAB:\n\t tabKeyPressedOnRedactorsZone_(event);break;\n\t case editor.core.keys.ENTER:\n\t enterKeyPressedOnRedactorsZone_(event);break;\n\t case editor.core.keys.ESC:\n\t escapeKeyPressedOnRedactorsZone_(event);break;\n\t default:\n\t defaultKeyPressedOnRedactorsZone_(event);break;\n\t }\n\t };\n\t\n\t /**\n\t * used by UI module\n\t * @description Routes all keyup events\n\t * @param {Object} event\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 arrowKeyPressed_(event);break;\n\t }\n\t };\n\t\n\t /**\n\t * @param {Object} event\n\t * @private\n\t *\n\t * Handles behaviour when tab pressed\n\t * @description if Content is empty show toolbox (if it is closed) or leaf tools\n\t * uses Toolbars toolbox module to handle the situation\n\t */\n\t var tabKeyPressedOnRedactorsZone_ = function tabKeyPressedOnRedactorsZone_(event) {\n\t\n\t /**\n\t * Wait for solution. Would like to know the behaviour\n\t * @todo Add spaces\n\t */\n\t event.preventDefault();\n\t\n\t if (!editor.core.isBlockEmpty(editor.content.currentNode)) {\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\n\t /**\n\t * Handles global EnterKey Press\n\t * @see enterPressedOnBlock_\n\t * @param {Object} event\n\t */\n\t var enterKeyPressed_ = function enterKeyPressed_() {\n\t\n\t if (editor.content.editorAreaHightlighted) {\n\t\n\t /**\n\t * it means that we lose input index, saved index before is not correct\n\t * therefore we need to set caret when we insert new block\n\t */\n\t editor.caret.inputIndex = -1;\n\t\n\t enterPressedOnBlock_();\n\t }\n\t };\n\t\n\t /**\n\t * Callback for enter key pressing in first-level block area\n\t *\n\t * @param {Event} event\n\t * @private\n\t *\n\t * @description Inserts new block with initial type from settings\n\t */\n\t var enterPressedOnBlock_ = function enterPressedOnBlock_() {\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 /**\n\t * ENTER key handler\n\t *\n\t * @param {Object} event\n\t * @private\n\t *\n\t * @description Makes new block with initial type from settings\n\t */\n\t var enterKeyPressedOnRedactorsZone_ = function enterKeyPressedOnRedactorsZone_(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 /**\n\t * When toolbar is opened, select tool instead of making new paragraph\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 /**\n\t * Stop other listeners callback executions\n\t */\n\t event.stopPropagation();\n\t event.stopImmediatePropagation();\n\t\n\t return;\n\t }\n\t\n\t /**\n\t * Allow paragraph lineBreaks with shift enter\n\t * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation\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 /**\n\t * Allow making new <p> in same block by SHIFT+ENTER and forbids to prevent default browser behaviour\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 /**\n\t * Workaround situation when caret at the Text node that has some wrapper Elements\n\t * Split block cant handle this.\n\t * We need to save default behavior\n\t */\n\t isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true';\n\t\n\t /**\n\t * Split blocks when input has several nodes and caret placed in textNode\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 /**\n\t * Escape behaviour\n\t * @param event\n\t * @private\n\t *\n\t * @description Closes toolbox and toolbar. Prevents default behaviour\n\t */\n\t var escapeKeyPressedOnRedactorsZone_ = function escapeKeyPressedOnRedactorsZone_(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 /**\n\t * @param {Event} event\n\t * @private\n\t *\n\t * closes and moves toolbar\n\t */\n\t var arrowKeyPressed_ = function arrowKeyPressed_(event) {\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 /**\n\t * @private\n\t * @param {Event} event\n\t *\n\t * @description Closes all opened bars from toolbar.\n\t * If block is mark, clears highlightning\n\t */\n\t var defaultKeyPressedOnRedactorsZone_ = function defaultKeyPressedOnRedactorsZone_() {\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 /**\n\t * Handler when clicked on redactors area\n\t *\n\t * @protected\n\t * @param event\n\t *\n\t * @description Detects clicked area. If it is first-level block area, marks as detected and\n\t * on next enter press will be inserted new block\n\t * Otherwise, save carets position (input index) and put caret to the editable zone.\n\t *\n\t * @see detectWhenClickedOnFirstLevelBlockArea_\n\t *\n\t */\n\t callbacks.redactorClicked = function (event) {\n\t\n\t detectWhenClickedOnFirstLevelBlockArea_();\n\t\n\t editor.content.workingNodeChanged(event.target);\n\t editor.ui.saveInputs();\n\t\n\t var selectedText = editor.toolbar.inline.getSelectionText(),\n\t firstLevelBlock;\n\t\n\t /** If selection range took off, then we hide inline toolbar */\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 /**\n\t * If inputs in redactor does not exits, then we put input index 0 not -1\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 /** 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 } else {\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 /**\n\t * Move toolbar and open\n\t */\n\t editor.toolbar.move();\n\t editor.toolbar.open();\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 /**\n\t * This method allows to define, is caret in contenteditable element or not.\n\t *\n\t * @private\n\t *\n\t * @description Otherwise, if we get TEXT node from range container, that will means we have input index.\n\t * In this case we use default browsers behaviour (if plugin allows that) or overwritten action.\n\t * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always\n\t * specifies to the first-level block. Other cases we just ignore.\n\t */\n\t var detectWhenClickedOnFirstLevelBlockArea_ = function detectWhenClickedOnFirstLevelBlockArea_() {\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;\n\t }\n\t };\n\t\n\t /**\n\t * Toolbar button click handler\n\t *\n\t * @param {Object} event - cursor to the button\n\t * @protected\n\t *\n\t * @description gets current tool and calls render method\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 /**\n\t * Show or Hide toolbox when plus button is clicked\n\t */\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 /**\n\t * Block handlers for KeyDown events\n\t *\n\t * @protected\n\t * @param {Object} event\n\t *\n\t * Handles keydowns on block\n\t * @see blockRightOrDownArrowPressed_\n\t * @see backspacePressed_\n\t * @see blockLeftOrUpArrowPressed_\n\t */\n\t callbacks.blockKeydown = function (event) {\n\t\n\t var block = event.target; // event.target is 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 blockRightOrDownArrowPressed_(event);\n\t break;\n\t\n\t case editor.core.keys.BACKSPACE:\n\t backspacePressed_(block, event);\n\t break;\n\t\n\t case editor.core.keys.UP:\n\t case editor.core.keys.LEFT:\n\t blockLeftOrUpArrowPressed_(event);\n\t break;\n\t\n\t }\n\t };\n\t\n\t /**\n\t * RIGHT or DOWN keydowns on block\n\t *\n\t * @param {Object} event\n\t * @private\n\t *\n\t * @description watches the selection and gets closest editable element.\n\t * Uses method getDeepestTextNodeFromPosition to get the last node of next block\n\t * Sets caret if it is contenteditable\n\t */\n\t var blockRightOrDownArrowPressed_ = function blockRightOrDownArrowPressed_(event) {\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 /**\n\t * Founded contentEditable element doesn't have childs\n\t * Or maybe New created block\n\t */\n\t if (!focusedNode.textContent) {\n\t\n\t editor.caret.setToNextBlock(editableElementIndex);\n\t return;\n\t }\n\t\n\t /**\n\t * Do nothing when caret doesn not reaches the end of last child\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 /**\n\t * LEFT or UP keydowns on block\n\t *\n\t * @param {Object} event\n\t * @private\n\t *\n\t * watches the selection and gets closest editable element.\n\t * Uses method getDeepestTextNodeFromPosition to get the last node of previous block\n\t * Sets caret if it is contenteditable\n\t *\n\t */\n\t var blockLeftOrUpArrowPressed_ = function blockLeftOrUpArrowPressed_(event) {\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 /**\n\t * LEFT or UP not at the beginning\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 /**\n\t * Do nothing if caret is not at the beginning of first child\n\t */\n\t var caretInFirstChild = false,\n\t caretAtTheBeginning = false;\n\t\n\t var firstChild, deepestTextnode;\n\t\n\t /**\n\t * Founded contentEditable element doesn't have childs\n\t * Or maybe New created block\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 /**\n\t * Handles backspace keydown\n\t *\n\t * @param {Element} block\n\t * @param {Object} event\n\t * @private\n\t *\n\t * @description if block is empty, delete the block and set caret to the previous block\n\t * If block is not empty, try to merge two blocks - current and previous\n\t * But it we try'n to remove first block, then we should set caret to the next block, not previous.\n\t * If we removed the last block, create new one\n\t */\n\t var backspacePressed_ = function backspacePressed_(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 (editor.core.isNativeInput(event.target)) {\n\t\n\t /** If input value is empty - remove block */\n\t if (event.target.value.trim() == '') {\n\t\n\t block.remove();\n\t } else {\n\t\n\t return;\n\t }\n\t }\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 /**\n\t * If all blocks are removed\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 /**\n\t * used by UI module\n\t * Clicks on block settings button\n\t *\n\t * @param {Object} event\n\t * @protected\n\t * @description Opens toolbar settings\n\t */\n\t callbacks.showSettingsButtonClicked = function (event) {\n\t\n\t /**\n\t * Get type of current block\n\t * It uses to append settings from tool.settings property.\n\t * ...\n\t * Type is stored in data-type attribute on block\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/**\n\t * Codex Editor Draw module\n\t *\n\t * @author Codex Team\n\t * @version 1.0.\n\t */\n\t\n\tmodule.exports = function (draw) {\n\t\n\t /**\n\t * Base editor wrapper\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 /**\n\t * Content-editable holder\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 /**\n\t * Empty toolbar with toggler\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 /**\n\t * Inline toolbar\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 /**\n\t * Wrapper for inline toobar buttons\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 /**\n\t * For some actions\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 /**\n\t * @todo Desc\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 /**\n\t * Block settings panel\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 /**\n\t * Settings button in toolbar\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 /**\n\t * Redactor tools wrapper\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 /**\n\t * @protected\n\t *\n\t * Draws tool buttons for toolbox\n\t *\n\t * @param {String} type\n\t * @param {String} classname\n\t * @returns {Element}\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 /**\n\t * @protected\n\t *\n\t * Draws tools for inline toolbar\n\t *\n\t * @param {String} type\n\t * @param {String} classname\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 /**\n\t * Redactor block\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 /**\n\t * Creates Node with passed tagName and className\n\t * @param {string} tagName\n\t * @param {string} className\n\t * @param {object} properties - allow to assign properties\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 /**\n\t * Unavailable plugin block\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/**\n\t * Codex Editor Caret Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (caret) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * @var {int} InputIndex - editable element in DOM\n\t */\n\t caret.inputIndex = null;\n\t\n\t /**\n\t * @var {int} offset - caret position in a text node.\n\t */\n\t caret.offset = null;\n\t\n\t /**\n\t * @var {int} focusedNodeIndex - we get index of child node from first-level block\n\t */\n\t caret.focusedNodeIndex = null;\n\t\n\t /**\n\t * Creates Document Range and sets caret to the element.\n\t * @protected\n\t * @uses caret.save — if you need to save caret position\n\t * @param {Element} el - Changed Node.\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.contentEditable != 'true') {\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 /**\n\t * @protected\n\t * Updates index of input and saves it in caret object\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 && 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 /**\n\t * Returns current input index (caret object)\n\t */\n\t caret.getCurrentInputIndex = function () {\n\t\n\t return caret.inputIndex;\n\t };\n\t\n\t /**\n\t * @param {int} index - index of first-level block after that we set caret into next input\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 /**\n\t * When new Block created or deleted content of input\n\t * We should add some text node to set caret\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 /**\n\t * @param {int} index - index of target input.\n\t * Sets caret to input with this index\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 /**\n\t * When new Block created or deleted content of input\n\t * We should add some text node to set caret\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 /**\n\t * @param {int} index - index of input\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 /**\n\t * When new Block created or deleted content of input\n\t * We should add some text node to set caret\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 /**\n\t * Inserts node at the caret location\n\t * @param {HTMLElement|DocumentFragment} node\n\t */\n\t caret.insertNode = function (node) {\n\t\n\t var selection,\n\t range,\n\t lastNode = node;\n\t\n\t if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) {\n\t\n\t lastNode = node.lastChild;\n\t }\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(node);\n\t\n\t range.setStartAfter(lastNode);\n\t range.collapse(true);\n\t\n\t selection.removeAllRanges();\n\t selection.addRange(range);\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/**\n\t * Codex Editor Notification Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\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 /**\n\t * Error notificator. Shows block with message\n\t * @protected\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 /**\n\t *\n\t * Appends notification\n\t *\n\t * settings = {\n\t * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\n\t * message - notification message\n\t * okMsg - confirm button text (default - 'Ok')\n\t * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\n\t * confirm - function-handler for ok button click\n\t * cancel - function-handler for cancel button click. Only for confirm and prompt types\n\t * time - time (in seconds) after which notification will close (default - 10s)\n\t * }\n\t *\n\t * @param settings\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 /**\n\t * Show notification block\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 /**\n\t * Remove notification block\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/**\n\t * Codex Editor Parser Module\n\t *\n\t * @author Codex Team\n\t * @version 1.1\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 /**\n\t * Check DOM node for display style: separated block or child-view\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/**\n\t * Codex Sanitizer\n\t */\n\t\n\tmodule.exports = function (sanitizer) {\n\t\n\t /** HTML Janitor library */\n\t var janitor = __webpack_require__(18);\n\t\n\t /** Codex Editor */\n\t var editor = codex.editor;\n\t\n\t sanitizer.prepare = function () {\n\t\n\t if (editor.settings.sanitizer && !editor.core.isEmpty(editor.settings.sanitizer)) {\n\t\n\t Config.CUSTOM = editor.settings.sanitizer;\n\t }\n\t };\n\t\n\t /**\n\t * Basic config\n\t */\n\t var Config = {\n\t\n\t /** User configuration */\n\t CUSTOM: null,\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 }\n\t }\n\t };\n\t\n\t sanitizer.Config = Config;\n\t\n\t /**\n\t *\n\t * @param userCustomConfig\n\t * @returns {*}\n\t * @private\n\t *\n\t * @description If developer uses editor's API, then he can customize sane restrictions.\n\t * Or, sane config can be defined globally in editors initialization. That config will be used everywhere\n\t * At least, if there is no config overrides, that API uses BASIC Default configation\n\t */\n\t var init_ = function init_(userCustomConfig) {\n\t\n\t var configuration = userCustomConfig || Config.CUSTOM || Config.BASIC;\n\t\n\t return new janitor(configuration);\n\t };\n\t\n\t /**\n\t * Cleans string from unwanted tags\n\t * @protected\n\t * @param {String} dirtyString - taint string\n\t * @param {Object} customConfig - allowed tags\n\t */\n\t sanitizer.clean = function (dirtyString, customConfig) {\n\t\n\t var janitorInstance = init_(customConfig);\n\t\n\t return janitorInstance.clean(dirtyString);\n\t };\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/**\n\t * Codex Editor Listeners module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\t/**\n\t * Module-decorator for event listeners assignment\n\t */\n\tmodule.exports = function (listeners) {\n\t\n\t var allListeners = [];\n\t\n\t /**\n\t * Search methods\n\t *\n\t * byElement, byType and byHandler returns array of suitable listeners\n\t * one and all takes element, eventType, and handler and returns first (all) suitable listener\n\t *\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/* 20 */\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/**\n\t * Codex Editor Destroyer module\n\t *\n\t * @auhor Codex Team\n\t * @version 1.0\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 /**\n\t * Delete editor data from webpage.\n\t * You should send settings argument with boolean flags:\n\t * @param settings.ui- remove redactor event listeners and DOM nodes\n\t * @param settings.scripts - remove redactor scripts from DOM\n\t * @param settings.plugins - remove plugin's objects\n\t * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\n\t * }\n\t *\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/* 21 */\n/***/ (function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Paste module\n\t *\n\t * @author Codex Team\n\t * @version 1.1.1\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 /**\n\t * Saves data\n\t * @param event\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 /**\n\t * Analizes pated string and calls necessary method\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 /**\n\t * This method prevents default behaviour.\n\t *\n\t * @param {Object} event\n\t * @protected\n\t *\n\t * @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.\n\t * Firstly, we need to memorize the caret position. We can do that by getting the range of selection.\n\t * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node\n\t */\n\t paste.blockPasteCallback = function (event) {\n\t\n\t if (!needsToHandlePasteEvent(event.target)) {\n\t\n\t return;\n\t }\n\t\n\t /** Prevent default behaviour */\n\t event.preventDefault();\n\t\n\t /** get html pasted data - dirty data */\n\t var htmlData = event.clipboardData.getData('text/html'),\n\t plainData = event.clipboardData.getData('text/plain');\n\t\n\t /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/\n\t var paragraphs = editor.draw.node('DIV', '', {}),\n\t cleanData,\n\t wrappedData;\n\t\n\t /** Create fragment, that we paste to range after proccesing */\n\t cleanData = editor.sanitizer.clean(htmlData);\n\t\n\t /**\n\t * We wrap pasted text with <p> tags to split it logically\n\t * @type {string}\n\t */\n\t wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData);\n\t paragraphs.innerHTML = wrappedData;\n\t\n\t /**\n\t * If there only one paragraph, just insert in at the caret location\n\t */\n\t if (paragraphs.childNodes.length == 1) {\n\t\n\t emulateUserAgentBehaviour(paragraphs.firstChild);\n\t return;\n\t }\n\t\n\t insertPastedParagraphs(paragraphs.childNodes);\n\t };\n\t\n\t /**\n\t * Checks if we should handle paste event on block\n\t * @param block\n\t *\n\t * @return {boolean}\n\t */\n\t var needsToHandlePasteEvent = function needsToHandlePasteEvent(block) {\n\t\n\t /** If area is input or textarea then allow default behaviour */\n\t if (editor.core.isNativeInput(block)) {\n\t\n\t return false;\n\t }\n\t\n\t var editableParent = editor.content.getEditableParent(block);\n\t\n\t /** Allow paste when event target placed in Editable element */\n\t if (!editableParent) {\n\t\n\t return false;\n\t }\n\t\n\t return true;\n\t };\n\t\n\t /**\n\t * Inserts new initial plugin blocks with data in paragraphs\n\t *\n\t * @param {Array} paragraphs - array of paragraphs (<p></p>) whit content, that should be inserted\n\t */\n\t var insertPastedParagraphs = function insertPastedParagraphs(paragraphs) {\n\t\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin,\n\t currentNode = editor.content.currentNode;\n\t\n\t paragraphs.forEach(function (paragraph) {\n\t\n\t /** Don't allow empty paragraphs */\n\t if (editor.core.isBlockEmpty(paragraph)) {\n\t\n\t return;\n\t }\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: paragraph.innerHTML\n\t })\n\t });\n\t\n\t editor.caret.inputIndex++;\n\t });\n\t\n\t editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1);\n\t\n\t /**\n\t * If there was no data in working node, remove it\n\t */\n\t if (editor.core.isBlockEmpty(currentNode)) {\n\t\n\t currentNode.remove();\n\t editor.ui.saveInputs();\n\t }\n\t };\n\t\n\t /**\n\t * Inserts node content at the caret position\n\t *\n\t * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location\n\t */\n\t var emulateUserAgentBehaviour = function emulateUserAgentBehaviour(node) {\n\t\n\t var newNode;\n\t\n\t if (node.childElementCount) {\n\t\n\t newNode = document.createDocumentFragment();\n\t\n\t node.childNodes.forEach(function (current) {\n\t\n\t if (!editor.core.isDomNode(current) && current.data.trim() === '') {\n\t\n\t return;\n\t }\n\t\n\t newNode.appendChild(current.cloneNode(true));\n\t });\n\t } else {\n\t\n\t newNode = document.createTextNode(node.textContent);\n\t }\n\t\n\t editor.caret.insertNode(newNode);\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 804711f99558afed9516","/**\n *\n * Codex Editor\n *\n * @author Codex Team\n */\n\nmodule.exports = (function (editor) {\n\n 'use strict';\n\n editor.version = VERSION;\n editor.scriptPrefix = 'cdx-script-';\n\n var init = function () {\n\n editor.core = require('./modules/core');\n editor.tools = require('./modules/tools');\n editor.ui = require('./modules/ui');\n editor.transport = require('./modules/transport');\n editor.renderer = require('./modules/renderer');\n editor.saver = require('./modules/saver');\n editor.content = require('./modules/content');\n editor.toolbar = require('./modules/toolbar/toolbar');\n editor.callback = require('./modules/callbacks');\n editor.draw = require('./modules/draw');\n editor.caret = require('./modules/caret');\n editor.notifications = require('./modules/notifications');\n editor.parser = require('./modules/parser');\n editor.sanitizer = require('./modules/sanitizer');\n editor.listeners = require('./modules/listeners');\n editor.destroyer = require('./modules/destroyer');\n editor.paste = require('./modules/paste');\n\n };\n\n /**\n * @public\n * holds initial settings\n */\n editor.settings = {\n tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n holderId : 'codex-editor',\n\n // Type of block showing on empty editor\n initialBlockPlugin: 'paragraph'\n };\n\n /**\n * public\n *\n * Static nodes\n */\n editor.nodes = {\n holder : null,\n wrapper : null,\n toolbar : null,\n inlineToolbar : {\n wrapper : null,\n buttons : null,\n actions : null\n },\n toolbox : null,\n notifications : null,\n plusButton : null,\n showSettingsButton: null,\n showTrashButton : null,\n blockSettings : null,\n pluginSettings : null,\n defaultSettings : null,\n toolbarButtons : {}, // { type : DomEl, ... }\n redactor : null\n };\n\n /**\n * @public\n *\n * Output state\n */\n editor.state = {\n jsonOutput : [],\n blocks : [],\n inputs : []\n };\n\n /**\n * @public\n * Editor plugins\n */\n editor.tools = {};\n\n /**\n * Initialization\n * @uses Promise cEditor.core.prepare\n * @param {Object} userSettings\n * @param {Array} userSettings.tools list of plugins\n * @param {String} userSettings.holderId Element's id to append editor\n *\n * Load user defined tools\n * Tools must contain this important objects :\n * @param {String} type - this is a type of plugin. It can be used as plugin name\n * @param {String} iconClassname - this a icon in toolbar\n * @param {Object} make - what should plugin do, when it is clicked\n * @param {Object} appendCallback - callback after clicking\n * @param {Element} settings - what settings does it have\n * @param {Object} render - plugin get JSON, and should return HTML\n * @param {Object} save - plugin gets HTML content, returns JSON\n * @param {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\n * @param {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\n *\n * @example\n * - type : 'header',\n * - iconClassname : 'ce-icon-header',\n * - make : headerTool.make,\n * - appendCallback : headerTool.appendCallback,\n * - settings : headerTool.makeSettings(),\n * - render : headerTool.render,\n * - save : headerTool.save,\n * - displayInToolbox : true,\n * - enableLineBreaks : false\n */\n editor.start = function (userSettings) {\n\n init();\n\n editor.core.prepare(userSettings)\n\n // If all ok, make UI, bind events and parse initial-content\n .then(editor.ui.prepare)\n .then(editor.tools.prepare)\n .then(editor.sanitizer.prepare)\n .then(editor.paste.prepare)\n .then(editor.transport.prepare)\n .then(editor.renderer.makeBlocksFromData)\n .then(editor.ui.saveInputs)\n .catch(function (error) {\n\n editor.core.log('Initialization failed with error: %o', 'warn', error);\n\n });\n\n };\n\n return editor;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./codex.js","/**\n * Codex Editor Core\n *\n * @author Codex Team\n * @version 1.1.3\n */\n\nmodule.exports = (function (core) {\n\n let editor = codex.editor;\n\n /**\n * @public\n *\n * Editor preparing method\n * @return Promise\n */\n core.prepare = function (userSettings) {\n\n return new Promise(function (resolve, reject) {\n\n if ( userSettings ) {\n\n editor.settings.tools = userSettings.tools || editor.settings.tools;\n\n }\n\n if (userSettings.data) {\n\n editor.state.blocks = userSettings.data;\n\n }\n\n if (userSettings.initialBlockPlugin) {\n\n editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\n\n }\n\n if (userSettings.sanitizer) {\n\n editor.settings.sanitizer = userSettings.sanitizer;\n\n }\n\n editor.hideToolbar = userSettings.hideToolbar;\n\n editor.settings.placeholder = userSettings.placeholder || '';\n\n editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId);\n\n if (typeof editor.nodes.holder === undefined || editor.nodes.holder === null) {\n\n reject(Error(\"Holder wasn't found by ID: #\" + userSettings.holderId));\n\n } else {\n\n resolve();\n\n }\n\n });\n\n };\n\n /**\n * Logging method\n * @param type = ['log', 'info', 'warn']\n */\n core.log = function (msg, type, arg) {\n\n type = type || 'log';\n\n if (!arg) {\n\n arg = msg || 'undefined';\n msg = '[codex-editor]: %o';\n\n } else {\n\n msg = '[codex-editor]: ' + msg;\n\n }\n\n try{\n\n if ( 'console' in window && window.console[ type ] ) {\n\n if ( arg ) window.console[ type ]( msg, arg );\n else window.console[ type ]( msg );\n\n }\n\n }catch(e) {}\n\n };\n\n /**\n * @protected\n *\n * Helper for insert one element after another\n */\n core.insertAfter = function (target, element) {\n\n target.parentNode.insertBefore(element, target.nextSibling);\n\n };\n\n /**\n * @const\n *\n * Readable DOM-node types map\n */\n core.nodeTypes = {\n TAG : 1,\n TEXT : 3,\n COMMENT : 8,\n DOCUMENT_FRAGMENT: 11\n };\n\n /**\n * @const\n * Readable keys map\n */\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 };\n\n /**\n * @protected\n *\n * Check object for DOM node\n */\n core.isDomNode = function (el) {\n\n return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG;\n\n };\n\n /**\n * Checks passed object for emptiness\n * @require ES5 - Object.keys\n * @param {object}\n */\n core.isEmpty = function ( obj ) {\n\n return Object.keys(obj).length === 0;\n\n };\n\n /**\n * Native Ajax\n * @param {String} settings.url - request URL\n * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks\n * @param {function} settings.success\n * @param {function} settings.progress\n */\n core.ajax = function (settings) {\n\n if (!settings || !settings.url) {\n\n return;\n\n }\n\n var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\n encodedString,\n isFormData,\n prop;\n\n\n settings.async = true;\n settings.type = settings.type || 'GET';\n settings.data = settings.data || '';\n settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8';\n\n if (settings.type == 'GET' && settings.data) {\n\n settings.url = /\\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data;\n\n } else {\n\n encodedString = '';\n for(prop in settings.data) {\n\n encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&');\n\n }\n\n }\n\n if (settings.withCredentials) {\n\n XMLHTTP.withCredentials = true;\n\n }\n\n /**\n * Value returned in beforeSend funtion will be passed as context to the other response callbacks\n * If beforeSend returns false, AJAX will be blocked\n */\n let responseContext,\n beforeSendResult;\n\n if (typeof settings.beforeSend === 'function') {\n\n beforeSendResult = settings.beforeSend.call();\n\n if (beforeSendResult === false) {\n\n return;\n\n }\n\n }\n\n XMLHTTP.open( settings.type, settings.url, settings.async );\n\n /**\n * If we send FormData, we need no content-type header\n */\n isFormData = isFormData_(settings.data);\n\n if (!isFormData) {\n\n if (settings.type !== 'POST') {\n\n XMLHTTP.setRequestHeader('Content-type', settings['content-type']);\n\n } else {\n\n XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n\n }\n\n }\n\n XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\n responseContext = beforeSendResult || XMLHTTP;\n\n if (typeof settings.progress === 'function') {\n\n XMLHTTP.upload.onprogress = settings.progress.bind(responseContext);\n\n }\n\n XMLHTTP.onreadystatechange = function () {\n\n if (XMLHTTP.readyState === 4) {\n\n if (XMLHTTP.status === 200) {\n\n if (typeof settings.success === 'function') {\n\n settings.success.call(responseContext, XMLHTTP.responseText);\n\n }\n\n } else {\n\n if (typeof settings.error === 'function') {\n\n settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status);\n\n }\n\n }\n\n }\n\n };\n\n if (isFormData) {\n\n // Sending FormData\n XMLHTTP.send(settings.data);\n\n } else {\n\n // POST requests\n XMLHTTP.send(encodedString);\n\n }\n\n return XMLHTTP;\n\n };\n\n /**\n * Appends script to head of document\n * @return Promise\n */\n core.importScript = function (scriptPath, instanceName) {\n\n return new Promise(function (resolve, reject) {\n\n let script;\n\n /** Script is already loaded */\n if ( !instanceName ) {\n\n reject('Instance name is missed');\n\n } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) {\n\n resolve(scriptPath);\n\n }\n\n script = document.createElement('SCRIPT');\n script.async = true;\n script.defer = true;\n script.id = editor.scriptPrefix + instanceName;\n\n script.onload = function () {\n\n resolve(scriptPath);\n\n };\n\n script.onerror = function () {\n\n reject(scriptPath);\n\n };\n\n script.src = scriptPath;\n document.head.appendChild(script);\n\n });\n\n };\n\n /**\n * Function for checking is it FormData object to send.\n * @param {Object} object to check\n * @return boolean\n */\n var isFormData_ = function (object) {\n\n return object instanceof FormData;\n\n };\n\n /**\n * Check block\n * @param target\n * @description Checks target is it native input\n */\n core.isNativeInput = function (target) {\n\n var nativeInputAreas = ['INPUT', 'TEXTAREA'];\n\n return nativeInputAreas.indexOf(target.tagName) != -1;\n\n };\n\n /**\n * Check if block is empty\n * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME\n *\n * @param block\n * @returns {boolean}\n */\n core.isBlockEmpty = function (block) {\n\n const EXCEPTION_TAGS = ['IMG', 'IFRAME'];\n\n var nativeInputs = block.querySelectorAll('textarea, input'),\n nativeInputsAreEmpty = true,\n textContentIsEmpty = !block.textContent.trim();\n\n Array.prototype.forEach.call(nativeInputs, function (input) {\n\n if (input.type == 'textarea' || input.type == 'text') {\n\n nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim();\n\n }\n\n });\n\n return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName);\n\n };\n\n\n return core;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/core.js","/**\n* Module working with plugins\n*/\nmodule.exports = (function () {\n\n let editor = codex.editor;\n\n /**\n * Initialize plugins before using\n * Ex. Load scripts or call some internal methods\n * @return Promise\n */\n function prepare() {\n\n return new Promise(function (resolve_, reject_) {\n\n Promise.resolve()\n\n /**\n * Compose a sequence of plugins that requires preparation\n */\n .then(function () {\n\n let pluginsRequiresPreparation = [],\n allPlugins = editor.tools;\n\n for ( let pluginName in allPlugins ) {\n\n let plugin = allPlugins[pluginName];\n\n if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {\n\n continue;\n\n }\n\n pluginsRequiresPreparation.push(plugin);\n\n }\n\n /**\n * If no one passed plugins requires preparation, finish prepare() and go ahead\n */\n if (!pluginsRequiresPreparation.length) {\n\n resolve_();\n\n }\n\n return pluginsRequiresPreparation;\n\n })\n\n /** Wait plugins while they prepares */\n .then(waitAllPluginsPreparation_)\n\n .then(function () {\n\n editor.core.log('Plugins loaded', 'info');\n resolve_();\n\n }).catch(function (error) {\n\n reject_(error);\n\n });\n\n });\n\n }\n\n /**\n * @param {array} plugins - list of tools that requires preparation\n * @return {Promise} resolved while all plugins will be ready or failed\n */\n function waitAllPluginsPreparation_(plugins) {\n\n /**\n * @calls allPluginsProcessed__ when all plugins prepared or failed\n */\n return new Promise (function (allPluginsProcessed__) {\n\n /**\n * pluck each element from queue\n * First, send resolved Promise as previous value\n * Each plugins \"prepare\" method returns a Promise, that's why\n * reduce current element will not be able to continue while can't get\n * a resolved Promise\n *\n * If last plugin is \"prepared\" then go to the next stage of initialization\n */\n plugins.reduce(function (previousValue, plugin, iteration) {\n\n return previousValue.then(function () {\n\n /**\n * Wait till plugins prepared\n * @calls pluginIsReady__ when plugin is ready or failed\n */\n return new Promise ( function (pluginIsReady__) {\n\n callPluginsPrepareMethod_( plugin )\n\n .then( pluginIsReady__ )\n .then( function () {\n\n plugin.available = true;\n\n })\n\n .catch(function (error) {\n\n editor.core.log(`Plugin «${plugin.type}» was not loaded. Preparation failed because %o`, 'warn', error);\n plugin.available = false;\n plugin.loadingMessage = error;\n\n /** Go ahead even some plugin has problems */\n pluginIsReady__();\n\n })\n\n .then(function () {\n\n /** If last plugin has problems then just ignore and continue */\n if (iteration == plugins.length - 1) {\n\n allPluginsProcessed__();\n\n }\n\n });\n\n });\n\n });\n\n }, Promise.resolve() );\n\n });\n\n }\n\n var callPluginsPrepareMethod_ = function (plugin) {\n\n return plugin.prepare( plugin.config || {} );\n\n };\n\n return {\n prepare: prepare\n };\n\n}());\n\n\n// WEBPACK FOOTER //\n// ./modules/tools.js","/**\n * Codex Editor UI module\n *\n * @author Codex Team\n * @version 1.2.0\n */\n\nmodule.exports = (function (ui) {\n\n let editor = codex.editor;\n\n /**\n * Basic editor classnames\n */\n ui.className = {\n\n /**\n * @const {string} BLOCK_CLASSNAME - redactor blocks name\n */\n BLOCK_CLASSNAME : 'ce-block',\n\n /**\n * @const {String} wrapper for plugins content\n */\n BLOCK_CONTENT : 'ce-block__content',\n\n /**\n * @const {String} BLOCK_STRETCHED - makes block stretched\n */\n BLOCK_STRETCHED : 'ce-block--stretched',\n\n /**\n * @const {String} BLOCK_HIGHLIGHTED - adds background\n */\n BLOCK_HIGHLIGHTED : 'ce-block--focused',\n\n /**\n * @const {String} - for all default settings\n */\n SETTINGS_ITEM : 'ce-settings__item'\n\n };\n\n /**\n * @protected\n *\n * Making main interface\n */\n ui.prepare = function () {\n\n return new Promise(function (resolve) {\n\n let wrapper = editor.draw.wrapper(),\n redactor = editor.draw.redactor(),\n toolbar = makeToolBar_();\n\n wrapper.appendChild(toolbar);\n wrapper.appendChild(redactor);\n\n /** Save created ui-elements to static nodes state */\n editor.nodes.wrapper = wrapper;\n editor.nodes.redactor = redactor;\n\n /** Append editor wrapper with redactor zone into holder */\n editor.nodes.holder.appendChild(wrapper);\n\n resolve();\n\n })\n\n /** Add toolbox tools */\n .then(addTools_)\n\n /** Make container for inline toolbar */\n .then(makeInlineToolbar_)\n\n /** Add inline toolbar tools */\n .then(addInlineToolbarTools_)\n\n /** Draw wrapper for notifications */\n .then(makeNotificationHolder_)\n\n /** Add eventlisteners to redactor elements */\n .then(bindEvents_)\n\n .catch( function () {\n\n editor.core.log(\"Can't draw editor interface\");\n\n });\n\n };\n\n /**\n * @private\n * Draws inline toolbar zone\n */\n var makeInlineToolbar_ = function () {\n\n var container = editor.draw.inlineToolbar();\n\n /** Append to redactor new inline block */\n editor.nodes.inlineToolbar.wrapper = container;\n\n /** Draw toolbar buttons */\n editor.nodes.inlineToolbar.buttons = editor.draw.inlineToolbarButtons();\n\n /** Buttons action or settings */\n editor.nodes.inlineToolbar.actions = editor.draw.inlineToolbarActions();\n\n /** Append to inline toolbar buttons as part of it */\n editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.buttons);\n editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.actions);\n\n editor.nodes.wrapper.appendChild(editor.nodes.inlineToolbar.wrapper);\n\n };\n\n var makeToolBar_ = function () {\n\n let toolbar = editor.draw.toolbar(),\n blockButtons = makeToolbarSettings_(),\n toolbarContent = makeToolbarContent_();\n\n /** Appending first-level block buttons */\n toolbar.appendChild(blockButtons);\n\n /** Append toolbarContent to toolbar */\n toolbar.appendChild(toolbarContent);\n\n /** Make toolbar global */\n editor.nodes.toolbar = toolbar;\n\n return toolbar;\n\n };\n\n var makeToolbarContent_ = function () {\n\n let toolbarContent = editor.draw.toolbarContent(),\n toolbox = editor.draw.toolbox(),\n plusButton = editor.draw.plusButton();\n\n /** Append plus button */\n toolbarContent.appendChild(plusButton);\n\n /** Appending toolbar tools */\n toolbarContent.appendChild(toolbox);\n\n /** Make Toolbox and plusButton global */\n editor.nodes.toolbox = toolbox;\n editor.nodes.plusButton = plusButton;\n\n return toolbarContent;\n\n };\n\n var makeToolbarSettings_ = function () {\n\n let blockSettings = editor.draw.blockSettings(),\n blockButtons = editor.draw.blockButtons(),\n defaultSettings = editor.draw.defaultSettings(),\n showSettingsButton = editor.draw.settingsButton(),\n showTrashButton = editor.toolbar.settings.makeRemoveBlockButton(),\n pluginSettings = editor.draw.pluginsSettings();\n\n /** Add default and plugins settings */\n blockSettings.appendChild(pluginSettings);\n blockSettings.appendChild(defaultSettings);\n\n /**\n * Make blocks buttons\n * This block contains settings button and remove block button\n */\n blockButtons.appendChild(showSettingsButton);\n blockButtons.appendChild(showTrashButton);\n blockButtons.appendChild(blockSettings);\n\n /** Make BlockSettings, PluginSettings, DefaultSettings global */\n editor.nodes.blockSettings = blockSettings;\n editor.nodes.pluginSettings = pluginSettings;\n editor.nodes.defaultSettings = defaultSettings;\n editor.nodes.showSettingsButton = showSettingsButton;\n editor.nodes.showTrashButton = showTrashButton;\n\n return blockButtons;\n\n };\n\n /** Draw notifications holder */\n var makeNotificationHolder_ = function () {\n\n /** Append block with notifications to the document */\n editor.nodes.notifications = editor.notifications.createHolder();\n\n };\n\n /**\n * @private\n * Append tools passed in editor.tools\n */\n var addTools_ = function () {\n\n var tool,\n toolName,\n toolButton;\n\n for ( toolName in editor.settings.tools ) {\n\n tool = editor.settings.tools[toolName];\n\n editor.tools[toolName] = tool;\n\n if (!tool.iconClassname && tool.displayInToolbox) {\n\n editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\n continue;\n\n }\n\n if (typeof tool.render != 'function') {\n\n editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\n continue;\n\n }\n\n if (!tool.displayInToolbox) {\n\n continue;\n\n } else {\n\n /** if tools is for toolbox */\n toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\n\n editor.nodes.toolbox.appendChild(toolButton);\n\n editor.nodes.toolbarButtons[toolName] = toolButton;\n\n }\n\n }\n\n };\n\n var addInlineToolbarTools_ = function () {\n\n var tools = {\n\n bold: {\n icon : 'ce-icon-bold',\n command : 'bold'\n },\n\n italic: {\n icon : 'ce-icon-italic',\n command : 'italic'\n },\n\n link: {\n icon : 'ce-icon-link',\n command : 'createLink'\n }\n };\n\n var toolButton,\n tool;\n\n for(var name in tools) {\n\n tool = tools[name];\n\n toolButton = editor.draw.toolbarButtonInline(name, tool.icon);\n\n editor.nodes.inlineToolbar.buttons.appendChild(toolButton);\n /**\n * Add callbacks to this buttons\n */\n editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);\n\n }\n\n };\n\n /**\n * @private\n * Bind editor UI events\n */\n var bindEvents_ = function () {\n\n editor.core.log('ui.bindEvents fired', 'info');\n\n // window.addEventListener('error', function (errorMsg, url, lineNumber) {\n // editor.notifications.errorThrown(errorMsg, event);\n // }, false );\n\n /** All keydowns on Document */\n editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n\n /** All keydowns on Redactor zone */\n editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n\n /** All keydowns on Document */\n editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );\n\n /**\n * Mouse click to radactor\n */\n editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );\n\n /**\n * Clicks to the Plus button\n */\n editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n\n /**\n * Clicks to SETTINGS button in toolbar\n */\n editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );\n\n /** Bind click listeners on toolbar buttons */\n for (var button in editor.nodes.toolbarButtons) {\n\n editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n\n }\n\n };\n\n ui.addBlockHandlers = function (block) {\n\n if (!block) return;\n\n /**\n * Block keydowns\n */\n editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n\n /**\n * Pasting content from another source\n * We have two type of sanitization\n * First - uses deep-first search algorithm to get sub nodes,\n * sanitizes whole Block_content and replaces cleared nodes\n * This method is deprecated\n * Method is used in editor.callback.blockPaste(event)\n *\n * Secont - uses Mutation observer.\n * Observer \"observe\" DOM changes and send changings to callback.\n * Callback gets changed node, not whole Block_content.\n * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n *\n * Method is used in editor.callback.blockPasteViaSanitize(event)\n *\n * @uses html-janitor\n * @example editor.callback.blockPasteViaSanitize(event), the second method.\n *\n */\n editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);\n\n /**\n * Show inline toolbar for selected text\n */\n editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\n editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);\n\n };\n\n /** getting all contenteditable elements */\n ui.saveInputs = function () {\n\n var redactor = editor.nodes.redactor;\n\n editor.state.inputs = [];\n\n /** Save all inputs in global variable state */\n var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\n\n Array.prototype.map.call(inputs, function (current) {\n\n if (!current.type || current.type == 'text' || current.type == 'textarea') {\n\n editor.state.inputs.push(current);\n\n }\n\n });\n\n };\n\n /**\n * Adds first initial block on empty redactor\n */\n ui.addInitialBlock = function () {\n\n var initialBlockType = editor.settings.initialBlockPlugin,\n initialBlock;\n\n if ( !editor.tools[initialBlockType] ) {\n\n editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\n return;\n\n }\n\n initialBlock = editor.tools[initialBlockType].render();\n\n initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);\n\n editor.content.insertBlock({\n type : initialBlockType,\n block : initialBlock\n });\n\n editor.content.workingNodeChanged(initialBlock);\n\n };\n\n ui.setInlineToolbarButtonBehaviour = function (button, type) {\n\n editor.listeners.add(button, 'mousedown', function (event) {\n\n editor.toolbar.inline.toolClicked(event, type);\n\n }, false);\n\n };\n\n return ui;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/ui.js","/**\n *\n * Codex.Editor Transport Module\n *\n * @copyright 2017 Codex-Team\n * @version 1.2.0\n */\n\nmodule.exports = (function (transport) {\n\n let editor = codex.editor;\n\n\n /**\n * @private {Object} current XmlHttpRequest instance\n */\n var currentRequest = null;\n\n\n /**\n * @type {null} | {DOMElement} input - keeps input element in memory\n */\n transport.input = null;\n\n /**\n * @property {Object} arguments - keep plugin settings and defined callbacks\n */\n transport.arguments = null;\n\n /**\n * Prepares input element where will be files\n */\n transport.prepare = function () {\n\n let input = editor.draw.node( 'INPUT', '', { type : 'file' } );\n\n editor.listeners.add(input, 'change', editor.transport.fileSelected);\n editor.transport.input = input;\n\n };\n\n /** Clear input when files is uploaded */\n transport.clearInput = function () {\n\n /** Remove old input */\n transport.input = null;\n\n /** Prepare new one */\n transport.prepare();\n\n };\n\n /**\n * Callback for file selection\n * @param {Event} event\n */\n transport.fileSelected = function () {\n\n var input = this,\n i,\n files = input.files,\n formData = new FormData();\n\n if (editor.transport.arguments.multiple === true) {\n\n for ( i = 0; i < files.length; i++) {\n\n formData.append('files[]', files[i], files[i].name);\n\n }\n\n } else {\n\n formData.append('files', files[0], files[0].name);\n\n }\n\n currentRequest = editor.core.ajax({\n type : 'POST',\n data : formData,\n url : editor.transport.arguments.url,\n beforeSend : editor.transport.arguments.beforeSend,\n success : editor.transport.arguments.success,\n error : editor.transport.arguments.error,\n progress : editor.transport.arguments.progress\n });\n\n /** Clear input */\n transport.clearInput();\n\n };\n\n /**\n * Use plugin callbacks\n * @protected\n *\n * @param {Object} args - can have :\n * @param {String} args.url - fetch URL\n * @param {Function} args.beforeSend - function calls before sending ajax\n * @param {Function} args.success - success callback\n * @param {Function} args.error - on error handler\n * @param {Function} args.progress - xhr onprogress handler\n * @param {Boolean} args.multiple - allow select several files\n * @param {String} args.accept - adds accept attribute\n */\n transport.selectAndUpload = function (args) {\n\n transport.arguments = args;\n\n if ( args.multiple === true) {\n\n transport.input.setAttribute('multiple', 'multiple');\n\n }\n\n if ( args.accept ) {\n\n transport.input.setAttribute('accept', args.accept);\n\n }\n\n transport.input.click();\n\n };\n\n transport.abort = function () {\n\n currentRequest.abort();\n\n currentRequest = null;\n\n };\n\n return transport;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/transport.js","/**\n * Codex Editor Renderer Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (renderer) {\n\n let editor = codex.editor;\n\n /**\n * Asyncronously parses input JSON to redactor blocks\n */\n renderer.makeBlocksFromData = function () {\n\n /**\n * If redactor is empty, add first paragraph to start writing\n */\n if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {\n\n editor.ui.addInitialBlock();\n return;\n\n }\n\n Promise.resolve()\n\n /** First, get JSON from state */\n .then(function () {\n\n return editor.state.blocks;\n\n })\n\n /** Then, start to iterate they */\n .then(editor.renderer.appendBlocks)\n\n /** Write log if something goes wrong */\n .catch(function (error) {\n\n editor.core.log('Error while parsing JSON: %o', 'error', error);\n\n });\n\n };\n\n /**\n * Parses JSON to blocks\n * @param {object} data\n * @return Primise -> nodeList\n */\n renderer.appendBlocks = function (data) {\n\n var blocks = data.items;\n\n /**\n * Sequence of one-by-one blocks appending\n * Uses to save blocks order after async-handler\n */\n var nodeSequence = Promise.resolve();\n\n for (var index = 0; index < blocks.length ; index++ ) {\n\n /** Add node to sequence at specified index */\n editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\n\n }\n\n };\n\n /**\n * Append node at specified index\n */\n renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\n\n /** We need to append node to sequence */\n nodeSequence\n\n /** first, get node async-aware */\n .then(function () {\n\n return editor.renderer.getNodeAsync(blocks, index);\n\n })\n\n /**\n * second, compose editor-block from JSON object\n */\n .then(editor.renderer.createBlockFromData)\n\n /**\n * now insert block to redactor\n */\n .then(function (blockData) {\n\n /**\n * blockData has 'block', 'type' and 'stretched' information\n */\n editor.content.insertBlock(blockData);\n\n /** Pass created block to next step */\n return blockData.block;\n\n })\n\n /** Log if something wrong with node */\n .catch(function (error) {\n\n editor.core.log('Node skipped while parsing because %o', 'error', error);\n\n });\n\n };\n\n /**\n * Asynchronously returns block data from blocksList by index\n * @return Promise to node\n */\n renderer.getNodeAsync = function (blocksList, index) {\n\n return Promise.resolve().then(function () {\n\n return {\n tool : blocksList[index],\n position : index\n };\n\n });\n\n };\n\n /**\n * Creates editor block by JSON-data\n *\n * @uses render method of each plugin\n *\n * @param {Object} toolData.tool\n * { header : {\n * text: '',\n * type: 'H3', ...\n * }\n * }\n * @param {Number} toolData.position - index in input-blocks array\n * @return {Object} with type and Element\n */\n renderer.createBlockFromData = function ( toolData ) {\n\n /** New parser */\n var block,\n tool = toolData.tool,\n pluginName = tool.type;\n\n /** Get first key of object that stores plugin name */\n // for (var pluginName in blockData) break;\n\n /** Check for plugin existance */\n if (!editor.tools[pluginName]) {\n\n throw Error(`Plugin «${pluginName}» not found`);\n\n }\n\n /** Check for plugin having render method */\n if (typeof editor.tools[pluginName].render != 'function') {\n\n throw Error(`Plugin «${pluginName}» must have «render» method`);\n\n }\n\n if ( editor.tools[pluginName].available === false ) {\n\n block = editor.draw.unavailableBlock();\n\n block.innerHTML = editor.tools[pluginName].loadingMessage;\n\n /**\n * Saver will extract data from initial block data by position in array\n */\n block.dataset.inputPosition = toolData.position;\n\n } else {\n\n /** New Parser */\n block = editor.tools[pluginName].render(tool.data);\n\n }\n\n /** is first-level block stretched */\n var stretched = editor.tools[pluginName].isStretched || false;\n\n /** Retrun type and block */\n return {\n type : pluginName,\n block : block,\n stretched : stretched\n };\n\n };\n\n return renderer;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/renderer.js","/**\n * Codex Editor Saver\n *\n * @author Codex Team\n * @version 1.1.0\n */\n\nmodule.exports = (function (saver) {\n\n let editor = codex.editor;\n\n /**\n * @public\n * Save blocks\n */\n saver.save = function () {\n\n /** Save html content of redactor to memory */\n editor.state.html = editor.nodes.redactor.innerHTML;\n\n /** Clean jsonOutput state */\n editor.state.jsonOutput = [];\n\n return saveBlocks(editor.nodes.redactor.childNodes);\n\n };\n\n /**\n * @private\n * Save each block data\n *\n * @param blocks\n * @returns {Promise.<TResult>}\n */\n let saveBlocks = function (blocks) {\n\n let data = [];\n\n for(let index = 0; index < blocks.length; index++) {\n\n data.push(getBlockData(blocks[index]));\n\n }\n\n return Promise.all(data)\n .then(makeOutput)\n .catch(editor.core.log);\n\n };\n\n /** Save and validate block data */\n let getBlockData = function (block) {\n\n return saveBlockData(block)\n .then(validateBlockData)\n .catch(editor.core.log);\n\n };\n\n /**\n * @private\n * Call block`s plugin save method and return saved data\n *\n * @param block\n * @returns {Object}\n */\n let saveBlockData = function (block) {\n\n let pluginName = block.dataset.tool;\n\n /** Check for plugin existence */\n if (!editor.tools[pluginName]) {\n\n editor.core.log(`Plugin «${pluginName}» not found`, 'error');\n return {data: null, pluginName: null};\n\n }\n\n /** Check for plugin having save method */\n if (typeof editor.tools[pluginName].save !== 'function') {\n\n editor.core.log(`Plugin «${pluginName}» must have save method`, 'error');\n return {data: null, pluginName: null};\n\n }\n\n /** Result saver */\n let blockContent = block.childNodes[0],\n pluginsContent = blockContent.childNodes[0],\n position = pluginsContent.dataset.inputPosition;\n\n /** If plugin wasn't available then return data from cache */\n if ( editor.tools[pluginName].available === false ) {\n\n return Promise.resolve({data: codex.editor.state.blocks.items[position].data, pluginName});\n\n }\n\n return Promise.resolve(pluginsContent)\n .then(editor.tools[pluginName].save)\n .then(data => Object({data, pluginName}));\n\n };\n\n /**\n * Call plugin`s validate method. Return false if validation failed\n *\n * @param data\n * @param pluginName\n * @returns {Object|Boolean}\n */\n let validateBlockData = function ({data, pluginName}) {\n\n if (!data || !pluginName) {\n\n return false;\n\n }\n\n if (editor.tools[pluginName].validate) {\n\n let result = editor.tools[pluginName].validate(data);\n\n /**\n * Do not allow invalid data\n */\n if (!result) {\n\n return false;\n\n }\n\n }\n\n return {data, pluginName};\n\n\n };\n\n /**\n * Compile article output\n *\n * @param savedData\n * @returns {{time: number, version, items: (*|Array)}}\n */\n let makeOutput = function (savedData) {\n\n savedData = savedData.filter(blockData => blockData);\n\n let items = savedData.map(blockData => Object({type: blockData.pluginName, data: blockData.data}));\n\n editor.state.jsonOutput = items;\n\n return {\n id: editor.state.blocks.id || null,\n time: +new Date(),\n version: editor.version,\n items\n };\n\n };\n\n return saver;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/saver.js","/**\n * Codex Editor Content Module\n * Works with DOM\n *\n * @module Codex Editor content module\n *\n * @author Codex Team\n * @version 1.3.13\n *\n * @description Module works with Elements that have been appended to the main DOM\n */\n\nmodule.exports = (function (content) {\n\n let editor = codex.editor;\n\n /**\n * Links to current active block\n * @type {null | Element}\n */\n content.currentNode = null;\n\n /**\n * clicked in redactor area\n * @type {null | Boolean}\n */\n content.editorAreaHightlighted = null;\n\n /**\n * @deprecated\n * Synchronizes redactor with original textarea\n */\n content.sync = function () {\n\n editor.core.log('syncing...');\n\n /**\n * Save redactor content to editor.state\n */\n editor.state.html = editor.nodes.redactor.innerHTML;\n\n };\n\n /**\n * Appends background to the block\n *\n * @description add CSS class to highlight visually first-level block area\n */\n content.markBlock = function () {\n\n editor.content.currentNode.classList.add(editor.ui.className.BLOCK_HIGHLIGHTED);\n\n };\n\n /**\n * Clear background\n *\n * @description clears styles that highlights block\n */\n content.clearMark = function () {\n\n if (editor.content.currentNode) {\n\n editor.content.currentNode.classList.remove(editor.ui.className.BLOCK_HIGHLIGHTED);\n\n }\n\n };\n\n /**\n * Finds first-level block\n *\n * @param {Element} node - selected or clicked in redactors area node\n * @protected\n *\n * @description looks for first-level block.\n * gets parent while node is not first-level\n */\n content.getFirstLevelBlock = function (node) {\n\n if (!editor.core.isDomNode(node)) {\n\n node = node.parentNode;\n\n }\n\n if (node === editor.nodes.redactor || node === document.body) {\n\n return null;\n\n } else {\n\n while(!node.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\n\n node = node.parentNode;\n\n }\n\n return node;\n\n }\n\n };\n\n /**\n * Trigger this event when working node changed\n * @param {Element} targetNode - first-level of this node will be current\n * @protected\n *\n * @description If targetNode is first-level then we set it as current else we look for parents to find first-level\n */\n content.workingNodeChanged = function (targetNode) {\n\n /** Clear background from previous marked block before we change */\n editor.content.clearMark();\n\n if (!targetNode) {\n\n return;\n\n }\n\n content.currentNode = content.getFirstLevelBlock(targetNode);\n\n };\n\n /**\n * Replaces one redactor block with another\n * @protected\n * @param {Element} targetBlock - block to replace. Mostly currentNode.\n * @param {Element} newBlock\n * @param {string} newBlockType - type of new block; we need to store it to data-attribute\n *\n * [!] Function does not saves old block content.\n * You can get it manually and pass with newBlock.innerHTML\n */\n content.replaceBlock = function (targetBlock, newBlock) {\n\n if (!targetBlock || !newBlock) {\n\n editor.core.log('replaceBlock: missed params');\n return;\n\n }\n\n /** If target-block is not a frist-level block, then we iterate parents to find it */\n while(!targetBlock.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\n\n targetBlock = targetBlock.parentNode;\n\n }\n\n /** Replacing */\n editor.nodes.redactor.replaceChild(newBlock, targetBlock);\n\n /**\n * Set new node as current\n */\n editor.content.workingNodeChanged(newBlock);\n\n /**\n * Add block handlers\n */\n editor.ui.addBlockHandlers(newBlock);\n\n /**\n * Save changes\n */\n editor.ui.saveInputs();\n\n };\n\n /**\n * @protected\n *\n * Inserts new block to redactor\n * Wrapps block into a DIV with BLOCK_CLASSNAME class\n *\n * @param blockData {object}\n * @param blockData.block {Element} element with block content\n * @param blockData.type {string} block plugin\n * @param needPlaceCaret {bool} pass true to set caret in new block\n *\n */\n content.insertBlock = function ( blockData, needPlaceCaret ) {\n\n var workingBlock = editor.content.currentNode,\n newBlockContent = blockData.block,\n blockType = blockData.type,\n isStretched = blockData.stretched;\n\n var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched);\n\n if (workingBlock) {\n\n editor.core.insertAfter(workingBlock, newBlock);\n\n } else {\n\n /**\n * If redactor is empty, append as first child\n */\n editor.nodes.redactor.appendChild(newBlock);\n\n }\n\n /**\n * Block handler\n */\n editor.ui.addBlockHandlers(newBlock);\n\n /**\n * Set new node as current\n */\n editor.content.workingNodeChanged(newBlock);\n\n /**\n * Save changes\n */\n editor.ui.saveInputs();\n\n\n if ( needPlaceCaret ) {\n\n /**\n * If we don't know input index then we set default value -1\n */\n var currentInputIndex = editor.caret.getCurrentInputIndex() || -1;\n\n\n if (currentInputIndex == -1) {\n\n\n var editableElement = newBlock.querySelector('[contenteditable]'),\n emptyText = document.createTextNode('');\n\n editableElement.appendChild(emptyText);\n editor.caret.set(editableElement, 0, 0);\n\n editor.toolbar.move();\n editor.toolbar.showPlusButton();\n\n\n } else {\n\n if (currentInputIndex === editor.state.inputs.length - 1)\n return;\n\n /** Timeout for browsers execution */\n window.setTimeout(function () {\n\n /** Setting to the new input */\n editor.caret.setToNextBlock(currentInputIndex);\n editor.toolbar.move();\n editor.toolbar.open();\n\n }, 10);\n\n }\n\n }\n\n /**\n * Block is inserted, wait for new click that defined focusing on editors area\n * @type {boolean}\n */\n content.editorAreaHightlighted = false;\n\n };\n\n /**\n * Replaces blocks with saving content\n * @protected\n * @param {Element} noteToReplace\n * @param {Element} newNode\n * @param {Element} blockType\n */\n content.switchBlock = function (blockToReplace, newBlock, tool) {\n\n tool = tool || editor.content.currentNode.dataset.tool;\n var newBlockComposed = composeNewBlock_(newBlock, tool);\n\n /** Replacing */\n editor.content.replaceBlock(blockToReplace, newBlockComposed);\n\n /** Save new Inputs when block is changed */\n editor.ui.saveInputs();\n\n };\n\n /**\n * Iterates between child noted and looking for #text node on deepest level\n * @protected\n *\n * @param {Element} block - node where find\n * @param {int} postiton - starting postion\n * Example: childNodex.length to find from the end\n * or 0 to find from the start\n * @return {Text} block\n * @uses DFS\n */\n content.getDeepestTextNodeFromPosition = function (block, position) {\n\n /**\n * Clear Block from empty and useless spaces with trim.\n * Such nodes we should remove\n */\n var blockChilds = block.childNodes,\n index,\n node,\n text;\n\n for(index = 0; index < blockChilds.length; index++) {\n\n node = blockChilds[index];\n\n if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\n text = node.textContent.trim();\n\n /** Text is empty. We should remove this child from node before we start DFS\n * decrease the quantity of childs.\n */\n if (text === '') {\n\n block.removeChild(node);\n position--;\n\n }\n\n }\n\n }\n\n if (block.childNodes.length === 0) {\n\n return document.createTextNode('');\n\n }\n\n /** Setting default position when we deleted all empty nodes */\n if ( position < 0 )\n position = 1;\n\n var lookingFromStart = false;\n\n /** For looking from START */\n if (position === 0) {\n\n lookingFromStart = true;\n position = 1;\n\n }\n\n while ( position ) {\n\n /** initial verticle of node. */\n if ( lookingFromStart ) {\n\n block = block.childNodes[0];\n\n } else {\n\n block = block.childNodes[position - 1];\n\n }\n\n if ( block.nodeType == editor.core.nodeTypes.TAG ) {\n\n position = block.childNodes.length;\n\n } else if (block.nodeType == editor.core.nodeTypes.TEXT ) {\n\n position = 0;\n\n }\n\n }\n\n return block;\n\n };\n\n /**\n * @private\n * @param {Element} block - current plugins render\n * @param {String} tool - plugins name\n * @param {Boolean} isStretched - make stretched block or not\n *\n * @description adds necessary information to wrap new created block by first-level holder\n */\n var composeNewBlock_ = function (block, tool, isStretched) {\n\n var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),\n blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});\n\n blockContent.appendChild(block);\n newBlock.appendChild(blockContent);\n\n if (isStretched) {\n\n blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED);\n\n }\n\n newBlock.dataset.tool = tool;\n return newBlock;\n\n };\n\n /**\n * Returns Range object of current selection\n * @protected\n */\n content.getRange = function () {\n\n var selection = window.getSelection().getRangeAt(0);\n\n return selection;\n\n };\n\n /**\n * Divides block in two blocks (after and before caret)\n *\n * @protected\n * @param {int} inputIndex - target input index\n *\n * @description splits current input content to the separate blocks\n * When enter is pressed among the words, that text will be splited.\n */\n content.splitBlock = function (inputIndex) {\n\n var selection = window.getSelection(),\n anchorNode = selection.anchorNode,\n anchorNodeText = anchorNode.textContent,\n caretOffset = selection.anchorOffset,\n textBeforeCaret,\n textNodeBeforeCaret,\n textAfterCaret,\n textNodeAfterCaret;\n\n var currentBlock = editor.content.currentNode.querySelector('[contentEditable]');\n\n\n textBeforeCaret = anchorNodeText.substring(0, caretOffset);\n textAfterCaret = anchorNodeText.substring(caretOffset);\n\n textNodeBeforeCaret = document.createTextNode(textBeforeCaret);\n\n if (textAfterCaret) {\n\n textNodeAfterCaret = document.createTextNode(textAfterCaret);\n\n }\n\n var previousChilds = [],\n nextChilds = [],\n reachedCurrent = false;\n\n if (textNodeAfterCaret) {\n\n nextChilds.push(textNodeAfterCaret);\n\n }\n\n for ( var i = 0, child; !!(child = currentBlock.childNodes[i]); i++) {\n\n if ( child != anchorNode ) {\n\n if ( !reachedCurrent ) {\n\n previousChilds.push(child);\n\n } else {\n\n nextChilds.push(child);\n\n }\n\n } else {\n\n reachedCurrent = true;\n\n }\n\n }\n\n /** Clear current input */\n editor.state.inputs[inputIndex].innerHTML = '';\n\n /**\n * Append all childs founded before anchorNode\n */\n var previousChildsLength = previousChilds.length;\n\n for(i = 0; i < previousChildsLength; i++) {\n\n editor.state.inputs[inputIndex].appendChild(previousChilds[i]);\n\n }\n\n editor.state.inputs[inputIndex].appendChild(textNodeBeforeCaret);\n\n /**\n * Append text node which is after caret\n */\n var nextChildsLength = nextChilds.length,\n newNode = document.createElement('div');\n\n for(i = 0; i < nextChildsLength; i++) {\n\n newNode.appendChild(nextChilds[i]);\n\n }\n\n newNode = newNode.innerHTML;\n\n /** This type of block creates when enter is pressed */\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n /**\n * Make new paragraph with text after caret\n */\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render({\n text : newNode\n })\n }, true );\n\n };\n\n /**\n * Merges two blocks — current and target\n * If target index is not exist, then previous will be as target\n *\n * @protected\n * @param {int} currentInputIndex\n * @param {int} targetInputIndex\n *\n * @description gets two inputs indexes and merges into one\n */\n content.mergeBlocks = function (currentInputIndex, targetInputIndex) {\n\n /** If current input index is zero, then prevent method execution */\n if (currentInputIndex === 0) {\n\n return;\n\n }\n\n var targetInput,\n currentInputContent = editor.state.inputs[currentInputIndex].innerHTML;\n\n if (!targetInputIndex) {\n\n targetInput = editor.state.inputs[currentInputIndex - 1];\n\n } else {\n\n targetInput = editor.state.inputs[targetInputIndex];\n\n }\n\n targetInput.innerHTML += currentInputContent;\n\n };\n\n /**\n * Iterates all right siblings and parents, which has right siblings\n * while it does not reached the first-level block\n *\n * @param {Element} node\n * @return {boolean}\n */\n content.isLastNode = function (node) {\n\n // console.log('погнали перебор родителей');\n\n var allChecked = false;\n\n while ( !allChecked ) {\n\n // console.log('Смотрим на %o', node);\n // console.log('Проверим, пустые ли соседи справа');\n\n if ( !allSiblingsEmpty_(node) ) {\n\n // console.log('Есть непустые соседи. Узел не последний. Выходим.');\n return false;\n\n }\n\n node = node.parentNode;\n\n /**\n * Проверяем родителей до тех пор, пока не найдем блок первого уровня\n */\n if ( node.classList.contains(editor.ui.className.BLOCK_CONTENT) ) {\n\n allChecked = true;\n\n }\n\n }\n\n return true;\n\n };\n\n /**\n * Checks if all element right siblings is empty\n * @param node\n */\n var allSiblingsEmpty_ = function (node) {\n\n /**\n * Нужно убедиться, что после пустого соседа ничего нет\n */\n var sibling = node.nextSibling;\n\n while ( sibling ) {\n\n if (sibling.textContent.length) {\n\n return false;\n\n }\n\n sibling = sibling.nextSibling;\n\n }\n\n return true;\n\n };\n\n /**\n * @public\n *\n * @param {string} htmlData - html content as string\n * @param {string} plainData - plain text\n * @return {string} - html content as string\n */\n content.wrapTextWithParagraphs = function (htmlData, plainData) {\n\n if (!htmlData.trim()) {\n\n return wrapPlainTextWithParagraphs(plainData);\n\n }\n\n var wrapper = document.createElement('DIV'),\n newWrapper = document.createElement('DIV'),\n i,\n paragraph,\n firstLevelBlocks = ['DIV', 'P'],\n blockTyped,\n node;\n\n /**\n * Make HTML Element to Wrap Text\n * It allows us to work with input data as HTML content\n */\n wrapper.innerHTML = htmlData;\n paragraph = document.createElement('P');\n\n for (i = 0; i < wrapper.childNodes.length; i++) {\n\n node = wrapper.childNodes[i];\n\n blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1;\n\n /**\n * If node is first-levet\n * we add this node to our new wrapper\n */\n if ( blockTyped ) {\n\n /**\n * If we had splitted inline nodes to paragraph before\n */\n if ( paragraph.childNodes.length ) {\n\n newWrapper.appendChild(paragraph.cloneNode(true));\n\n /** empty paragraph */\n paragraph = null;\n paragraph = document.createElement('P');\n\n }\n\n newWrapper.appendChild(node.cloneNode(true));\n\n } else {\n\n /** Collect all inline nodes to one as paragraph */\n paragraph.appendChild(node.cloneNode(true));\n\n /** if node is last we should append this node to paragraph and paragraph to new wrapper */\n if ( i == wrapper.childNodes.length - 1 ) {\n\n newWrapper.appendChild(paragraph.cloneNode(true));\n\n }\n\n }\n\n }\n\n return newWrapper.innerHTML;\n\n };\n\n /**\n * Splits strings on new line and wraps paragraphs with <p> tag\n * @param plainText\n * @returns {string}\n */\n var wrapPlainTextWithParagraphs = function (plainText) {\n\n if (!plainText) return '';\n\n return '<p>' + plainText.split('\\n\\n').join('</p><p>') + '</p>';\n\n };\n\n /**\n * Finds closest Contenteditable parent from Element\n * @param {Element} node element looking from\n * @return {Element} node contenteditable\n */\n content.getEditableParent = function (node) {\n\n while (node && node.contentEditable != 'true') {\n\n node = node.parentNode;\n\n }\n\n return node;\n\n };\n\n /**\n * Clear editors content\n *\n * @param {Boolean} all — if true, delete all article data (content, id, etc.)\n */\n content.clear = function (all) {\n\n editor.nodes.redactor.innerHTML = '';\n editor.content.sync();\n editor.ui.saveInputs();\n if (all) {\n\n editor.state.blocks = {};\n\n } else if (editor.state.blocks) {\n\n editor.state.blocks.items = [];\n\n }\n\n editor.content.currentNode = null;\n\n };\n\n /**\n *\n * Load new data to editor\n * If editor is not empty, just append articleData.items\n *\n * @param articleData.items\n */\n content.load = function (articleData) {\n\n var currentContent = Object.assign({}, editor.state.blocks);\n\n editor.content.clear();\n\n if (!Object.keys(currentContent).length) {\n\n editor.state.blocks = articleData;\n\n } else if (!currentContent.items) {\n\n currentContent.items = articleData.items;\n editor.state.blocks = currentContent;\n\n } else {\n\n currentContent.items = currentContent.items.concat(articleData.items);\n editor.state.blocks = currentContent;\n\n }\n\n editor.renderer.makeBlocksFromData();\n\n };\n\n return content;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/content.js","/**\n * Codex Editor toolbar module\n *\n * Contains:\n * - Inline toolbox\n * - Toolbox within plus button\n * - Settings section\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (toolbar) {\n\n let editor = codex.editor;\n\n toolbar.settings = require('./settings');\n toolbar.inline = require('./inline');\n toolbar.toolbox = require('./toolbox');\n\n /**\n * Margin between focused node and toolbar\n */\n toolbar.defaultToolbarHeight = 49;\n\n toolbar.defaultOffset = 34;\n\n toolbar.opened = false;\n\n toolbar.current = null;\n\n /**\n * @protected\n */\n toolbar.open = function () {\n\n if (editor.hideToolbar) {\n\n return;\n\n }\n\n let toolType = editor.content.currentNode.dataset.tool;\n\n if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {\n\n editor.nodes.showSettingsButton.classList.add('hide');\n\n } else {\n\n editor.nodes.showSettingsButton.classList.remove('hide');\n\n }\n\n editor.nodes.toolbar.classList.add('opened');\n this.opened = true;\n\n };\n\n /**\n * @protected\n */\n toolbar.close = function () {\n\n editor.nodes.toolbar.classList.remove('opened');\n\n toolbar.opened = false;\n toolbar.current = null;\n\n for (var button in editor.nodes.toolbarButtons) {\n\n editor.nodes.toolbarButtons[button].classList.remove('selected');\n\n }\n\n /** Close toolbox when toolbar is not displayed */\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.close();\n\n };\n\n toolbar.toggle = function () {\n\n if ( !this.opened ) {\n\n this.open();\n\n } else {\n\n this.close();\n\n }\n\n };\n\n toolbar.hidePlusButton = function () {\n\n editor.nodes.plusButton.classList.add('hide');\n\n };\n\n toolbar.showPlusButton = function () {\n\n editor.nodes.plusButton.classList.remove('hide');\n\n };\n\n /**\n * Moving toolbar to the specified node\n */\n toolbar.move = function () {\n\n /** Close Toolbox when we move toolbar */\n editor.toolbar.toolbox.close();\n\n if (!editor.content.currentNode) {\n\n return;\n\n }\n\n var newYCoordinate = editor.content.currentNode.offsetTop - (editor.toolbar.defaultToolbarHeight / 2) + editor.toolbar.defaultOffset;\n\n editor.nodes.toolbar.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;\n\n /** Close trash actions */\n editor.toolbar.settings.hideRemoveActions();\n\n };\n\n return toolbar;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/toolbar.js","/**\n * Toolbar settings\n *\n * @version 1.0.5\n */\n\nmodule.exports = (function (settings) {\n\n let editor = codex.editor;\n\n settings.opened = false;\n\n settings.setting = null;\n settings.actions = null;\n\n /**\n * Append and open settings\n */\n settings.open = function (toolType) {\n\n /**\n * Append settings content\n * It's stored in tool.settings\n */\n if ( !editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {\n\n return;\n\n }\n\n /**\n * Draw settings block\n */\n var settingsBlock = editor.tools[toolType].makeSettings();\n\n editor.nodes.pluginSettings.appendChild(settingsBlock);\n\n\n /** Open settings block */\n editor.nodes.blockSettings.classList.add('opened');\n this.opened = true;\n\n };\n\n /**\n * Close and clear settings\n */\n settings.close = function () {\n\n editor.nodes.blockSettings.classList.remove('opened');\n editor.nodes.pluginSettings.innerHTML = '';\n\n this.opened = false;\n\n };\n\n /**\n * @param {string} toolType - plugin type\n */\n settings.toggle = function ( toolType ) {\n\n if ( !this.opened ) {\n\n this.open(toolType);\n\n } else {\n\n this.close();\n\n }\n\n };\n\n /**\n * Here we will draw buttons and add listeners to components\n */\n settings.makeRemoveBlockButton = function () {\n\n var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}),\n settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML : '<i class=\"ce-icon-trash\"></i>' }),\n actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\n confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }),\n cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' });\n\n editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\n\n editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\n\n editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\n\n actionWrapper.appendChild(confirmAction);\n actionWrapper.appendChild(cancelAction);\n\n removeBlockWrapper.appendChild(settingButton);\n removeBlockWrapper.appendChild(actionWrapper);\n\n /** Save setting */\n editor.toolbar.settings.setting = settingButton;\n editor.toolbar.settings.actions = actionWrapper;\n\n return removeBlockWrapper;\n\n };\n\n settings.removeButtonClicked = function () {\n\n var action = editor.toolbar.settings.actions;\n\n if (action.classList.contains('opened')) {\n\n editor.toolbar.settings.hideRemoveActions();\n\n } else {\n\n editor.toolbar.settings.showRemoveActions();\n\n }\n\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.close();\n\n };\n\n settings.cancelRemovingRequest = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n settings.confirmRemovingRequest = function () {\n\n var currentBlock = editor.content.currentNode,\n firstLevelBlocksCount;\n\n currentBlock.remove();\n\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\n /**\n * If all blocks are removed\n */\n if (firstLevelBlocksCount === 0) {\n\n /** update currentNode variable */\n editor.content.currentNode = null;\n\n /** Inserting new empty initial block */\n editor.ui.addInitialBlock();\n\n }\n\n editor.ui.saveInputs();\n\n editor.toolbar.close();\n\n };\n\n settings.showRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.add('opened');\n\n };\n\n settings.hideRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n return settings;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/settings.js","/**\n * Inline toolbar\n *\n * Contains from tools:\n * Bold, Italic, Underline and Anchor\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (inline) {\n\n let editor = codex.editor;\n\n inline.buttonsOpened = null;\n inline.actionsOpened = null;\n inline.wrappersOffset = null;\n\n /**\n * saving selection that need for execCommand for styling\n *\n */\n inline.storedSelection = null;\n\n /**\n * @protected\n *\n * Open inline toobar\n */\n inline.show = function () {\n\n var currentNode = editor.content.currentNode,\n tool = currentNode.dataset.tool,\n plugin;\n\n /**\n * tool allowed to open inline toolbar\n */\n plugin = editor.tools[tool];\n\n if (!plugin.showInlineToolbar)\n return;\n\n var selectedText = inline.getSelectionText(),\n toolbar = editor.nodes.inlineToolbar.wrapper;\n\n if (selectedText.length > 0) {\n\n /** Move toolbar and open */\n editor.toolbar.inline.move();\n\n /** Open inline toolbar */\n toolbar.classList.add('opened');\n\n /** show buttons of inline toolbar */\n editor.toolbar.inline.showButtons();\n\n }\n\n };\n\n /**\n * @protected\n *\n * Closes inline toolbar\n */\n inline.close = function () {\n\n var toolbar = editor.nodes.inlineToolbar.wrapper;\n\n toolbar.classList.remove('opened');\n\n };\n\n /**\n * @private\n *\n * Moving toolbar\n */\n inline.move = function () {\n\n if (!this.wrappersOffset) {\n\n this.wrappersOffset = this.getWrappersOffset();\n\n }\n\n var coords = this.getSelectionCoords(),\n defaultOffset = 0,\n toolbar = editor.nodes.inlineToolbar.wrapper,\n newCoordinateX,\n newCoordinateY;\n\n if (!coords) {\n\n return;\n\n }\n\n if (toolbar.offsetHeight === 0) {\n\n defaultOffset = 40;\n\n }\n\n newCoordinateX = coords.x - this.wrappersOffset.left;\n newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;\n\n toolbar.style.transform = `translate3D(${Math.floor(newCoordinateX)}px, ${Math.floor(newCoordinateY)}px, 0)`;\n\n /** Close everything */\n editor.toolbar.inline.closeButtons();\n editor.toolbar.inline.closeAction();\n\n };\n\n /**\n * @private\n *\n * Tool Clicked\n */\n\n inline.toolClicked = function (event, type) {\n\n /**\n * For simple tools we use default browser function\n * For more complicated tools, we should write our own behavior\n */\n switch (type) {\n case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break;\n default : editor.toolbar.inline.defaultToolAction(type); break;\n }\n\n /**\n * highlight buttons\n * after making some action\n */\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\n };\n\n /**\n * @private\n *\n * Saving wrappers offset in DOM\n */\n inline.getWrappersOffset = function () {\n\n var wrapper = editor.nodes.wrapper,\n offset = this.getOffset(wrapper);\n\n this.wrappersOffset = offset;\n return offset;\n\n };\n\n /**\n * @private\n *\n * Calculates offset of DOM element\n *\n * @param el\n * @returns {{top: number, left: number}}\n */\n inline.getOffset = function ( el ) {\n\n var _x = 0;\n var _y = 0;\n\n while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {\n\n _x += (el.offsetLeft + el.clientLeft);\n _y += (el.offsetTop + el.clientTop);\n el = el.offsetParent;\n\n }\n return { top: _y, left: _x };\n\n };\n\n /**\n * @private\n *\n * Calculates position of selected text\n * @returns {{x: number, y: number}}\n */\n inline.getSelectionCoords = function () {\n\n var sel = document.selection, range;\n var x = 0, y = 0;\n\n if (sel) {\n\n if (sel.type != 'Control') {\n\n range = sel.createRange();\n range.collapse(true);\n x = range.boundingLeft;\n y = range.boundingTop;\n\n }\n\n } else if (window.getSelection) {\n\n sel = window.getSelection();\n\n if (sel.rangeCount) {\n\n range = sel.getRangeAt(0).cloneRange();\n if (range.getClientRects) {\n\n range.collapse(true);\n var rect = range.getClientRects()[0];\n\n if (!rect) {\n\n return;\n\n }\n\n x = rect.left;\n y = rect.top;\n\n }\n\n }\n\n }\n return { x: x, y: y };\n\n };\n\n /**\n * @private\n *\n * Returns selected text as String\n * @returns {string}\n */\n inline.getSelectionText = function () {\n\n var selectedText = '';\n\n // all modern browsers and IE9+\n if (window.getSelection) {\n\n selectedText = window.getSelection().toString();\n\n }\n\n return selectedText;\n\n };\n\n /** Opens buttons block */\n inline.showButtons = function () {\n\n var buttons = editor.nodes.inlineToolbar.buttons;\n\n buttons.classList.add('opened');\n\n editor.toolbar.inline.buttonsOpened = true;\n\n /** highlight buttons */\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\n };\n\n /** Makes buttons disappear */\n inline.closeButtons = function () {\n\n var buttons = editor.nodes.inlineToolbar.buttons;\n\n buttons.classList.remove('opened');\n\n editor.toolbar.inline.buttonsOpened = false;\n\n };\n\n /** Open buttons defined action if exist */\n inline.showActions = function () {\n\n var action = editor.nodes.inlineToolbar.actions;\n\n action.classList.add('opened');\n\n editor.toolbar.inline.actionsOpened = true;\n\n };\n\n /** Close actions block */\n inline.closeAction = function () {\n\n var action = editor.nodes.inlineToolbar.actions;\n\n action.innerHTML = '';\n action.classList.remove('opened');\n editor.toolbar.inline.actionsOpened = false;\n\n };\n\n\n /**\n * Callback for keydowns in inline toolbar \"Insert link...\" input\n */\n let inlineToolbarAnchorInputKeydown_ = function (event) {\n\n if (event.keyCode != editor.core.keys.ENTER) {\n\n return;\n\n }\n\n let editable = editor.content.currentNode,\n storedSelection = editor.toolbar.inline.storedSelection;\n\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\n editor.toolbar.inline.setAnchor(this.value);\n\n /**\n * Preventing events that will be able to happen\n */\n event.preventDefault();\n event.stopImmediatePropagation();\n\n editor.toolbar.inline.clearRange();\n\n };\n\n /** Action for link creation or for setting anchor */\n inline.createLinkAction = function (event) {\n\n var isActive = this.isLinkActive();\n\n var editable = editor.content.currentNode,\n storedSelection = editor.toolbar.inline.saveSelection(editable);\n\n /** Save globally selection */\n editor.toolbar.inline.storedSelection = storedSelection;\n\n if (isActive) {\n\n\n /**\n * Changing stored selection. if we want to remove anchor from word\n * we should remove anchor from whole word, not only selected part.\n * The solution is than we get the length of current link\n * Change start position to - end of selection minus length of anchor\n */\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\n editor.toolbar.inline.defaultToolAction('unlink');\n\n } else {\n\n /** Create input and close buttons */\n var action = editor.draw.inputForLink();\n\n editor.nodes.inlineToolbar.actions.appendChild(action);\n\n editor.toolbar.inline.closeButtons();\n editor.toolbar.inline.showActions();\n\n /**\n * focus to input\n * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\n * Prevents event after showing input and when we need to focus an input which is in unexisted form\n */\n action.focus();\n event.preventDefault();\n\n /** Callback to link action */\n editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);\n\n }\n\n };\n\n inline.isLinkActive = function () {\n\n var isActive = false;\n\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\n\n var dataType = tool.dataset.type;\n\n if (dataType == 'link' && tool.classList.contains('hightlighted')) {\n\n isActive = true;\n\n }\n\n });\n\n return isActive;\n\n };\n\n /** default action behavior of tool */\n inline.defaultToolAction = function (type) {\n\n document.execCommand(type, false, null);\n\n };\n\n /**\n * @private\n *\n * Sets URL\n *\n * @param {String} url - URL\n */\n inline.setAnchor = function (url) {\n\n document.execCommand('createLink', false, url);\n\n /** Close after URL inserting */\n editor.toolbar.inline.closeAction();\n\n };\n\n /**\n * @private\n *\n * Saves selection\n */\n inline.saveSelection = function (containerEl) {\n\n var range = window.getSelection().getRangeAt(0),\n preSelectionRange = range.cloneRange(),\n start;\n\n preSelectionRange.selectNodeContents(containerEl);\n preSelectionRange.setEnd(range.startContainer, range.startOffset);\n\n start = preSelectionRange.toString().length;\n\n return {\n start: start,\n end: start + range.toString().length\n };\n\n };\n\n /**\n * @private\n *\n * Sets to previous selection (Range)\n *\n * @param {Element} containerEl - editable element where we restore range\n * @param {Object} savedSel - range basic information to restore\n */\n inline.restoreSelection = function (containerEl, savedSel) {\n\n var range = document.createRange(),\n charIndex = 0;\n\n range.setStart(containerEl, 0);\n range.collapse(true);\n\n var nodeStack = [ containerEl ],\n node,\n foundStart = false,\n stop = false,\n nextCharIndex;\n\n while (!stop && (node = nodeStack.pop())) {\n\n if (node.nodeType == 3) {\n\n nextCharIndex = charIndex + node.length;\n\n if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\n\n range.setStart(node, savedSel.start - charIndex);\n foundStart = true;\n\n }\n if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\n\n range.setEnd(node, savedSel.end - charIndex);\n stop = true;\n\n }\n charIndex = nextCharIndex;\n\n } else {\n\n var i = node.childNodes.length;\n\n while (i--) {\n\n nodeStack.push(node.childNodes[i]);\n\n }\n\n }\n\n }\n\n var sel = window.getSelection();\n\n sel.removeAllRanges();\n sel.addRange(range);\n\n };\n\n /**\n * @private\n *\n * Removes all ranges from window selection\n */\n inline.clearRange = function () {\n\n var selection = window.getSelection();\n\n selection.removeAllRanges();\n\n };\n\n /**\n * @private\n *\n * sets or removes hightlight\n */\n inline.hightlight = function (tool) {\n\n var dataType = tool.dataset.type;\n\n if (document.queryCommandState(dataType)) {\n\n editor.toolbar.inline.setButtonHighlighted(tool);\n\n } else {\n\n editor.toolbar.inline.removeButtonsHighLight(tool);\n\n }\n\n /**\n *\n * hightlight for anchors\n */\n var selection = window.getSelection(),\n tag = selection.anchorNode.parentNode;\n\n if (tag.tagName == 'A' && dataType == 'link') {\n\n editor.toolbar.inline.setButtonHighlighted(tool);\n\n }\n\n };\n\n /**\n * @private\n *\n * Mark button if text is already executed\n */\n inline.setButtonHighlighted = function (button) {\n\n button.classList.add('hightlighted');\n\n /** At link tool we also change icon */\n if (button.dataset.type == 'link') {\n\n var icon = button.childNodes[0];\n\n icon.classList.remove('ce-icon-link');\n icon.classList.add('ce-icon-unlink');\n\n }\n\n };\n\n /**\n * @private\n *\n * Removes hightlight\n */\n inline.removeButtonsHighLight = function (button) {\n\n button.classList.remove('hightlighted');\n\n /** At link tool we also change icon */\n if (button.dataset.type == 'link') {\n\n var icon = button.childNodes[0];\n\n icon.classList.remove('ce-icon-unlink');\n icon.classList.add('ce-icon-link');\n\n }\n\n };\n\n\n return inline;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/inline.js","/**\n * Codex Editor toolbox\n *\n * All tools be able to appended here\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (toolbox) {\n\n let editor = codex.editor;\n\n toolbox.opened = false;\n toolbox.openedOnBlock = null;\n\n /** Shows toolbox */\n toolbox.open = function () {\n\n /** Close setting if toolbox is opened */\n if (editor.toolbar.settings.opened) {\n\n editor.toolbar.settings.close();\n\n }\n\n /** Add 'toolbar-opened' class for current block **/\n toolbox.openedOnBlock = editor.content.currentNode;\n toolbox.openedOnBlock.classList.add('toolbar-opened');\n\n /** display toolbox */\n editor.nodes.toolbox.classList.add('opened');\n\n /** Animate plus button */\n editor.nodes.plusButton.classList.add('clicked');\n\n /** toolbox state */\n editor.toolbar.toolbox.opened = true;\n\n };\n\n /** Closes toolbox */\n toolbox.close = function () {\n\n /** Remove 'toolbar-opened' class from current block **/\n if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened');\n toolbox.openedOnBlock = null;\n\n /** Makes toolbox disappear */\n editor.nodes.toolbox.classList.remove('opened');\n\n /** Rotate plus button */\n editor.nodes.plusButton.classList.remove('clicked');\n\n /** toolbox state */\n editor.toolbar.toolbox.opened = false;\n\n editor.toolbar.current = null;\n\n };\n\n toolbox.leaf = function () {\n\n let currentTool = editor.toolbar.current,\n tools = Object.keys(editor.tools),\n barButtons = editor.nodes.toolbarButtons,\n nextToolIndex = 0,\n toolToSelect,\n visibleTool,\n tool;\n\n if ( !currentTool ) {\n\n /** Get first tool from object*/\n for(tool in editor.tools) {\n\n if (editor.tools[tool].displayInToolbox) {\n\n break;\n\n }\n\n nextToolIndex ++;\n\n }\n\n } else {\n\n nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;\n visibleTool = tools[nextToolIndex];\n\n while (!editor.tools[visibleTool].displayInToolbox) {\n\n nextToolIndex = (nextToolIndex + 1) % tools.length;\n visibleTool = tools[nextToolIndex];\n\n }\n\n }\n\n toolToSelect = tools[nextToolIndex];\n\n for ( var button in barButtons ) {\n\n barButtons[button].classList.remove('selected');\n\n }\n\n barButtons[toolToSelect].classList.add('selected');\n editor.toolbar.current = toolToSelect;\n\n };\n\n /**\n * Transforming selected node type into selected toolbar element type\n * @param {event} event\n */\n toolbox.toolClicked = function (event) {\n\n /**\n * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty\n */\n var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],\n tool = editor.tools[editor.toolbar.current],\n workingNode = editor.content.currentNode,\n currentInputIndex = editor.caret.inputIndex,\n newBlockContent,\n appendCallback,\n blockData;\n\n /** Make block from plugin */\n newBlockContent = tool.render();\n\n /** information about block */\n blockData = {\n block : newBlockContent,\n type : tool.type,\n stretched : false\n };\n\n if (\n workingNode &&\n UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 &&\n workingNode.textContent.trim() === ''\n ) {\n\n /** Replace current block */\n editor.content.switchBlock(workingNode, newBlockContent, tool.type);\n\n } else {\n\n /** Insert new Block from plugin */\n editor.content.insertBlock(blockData);\n\n /** increase input index */\n currentInputIndex++;\n\n }\n\n /** Fire tool append callback */\n appendCallback = tool.appendCallback;\n\n if (appendCallback && typeof appendCallback == 'function') {\n\n appendCallback.call(event);\n\n }\n\n window.setTimeout(function () {\n\n /** Set caret to current block */\n editor.caret.setToBlock(currentInputIndex);\n\n }, 10);\n\n\n /**\n * Changing current Node\n */\n editor.content.workingNodeChanged();\n\n /**\n * Move toolbar when node is changed\n */\n editor.toolbar.move();\n\n };\n\n return toolbox;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/toolbox.js","/**\n * @module Codex Editor Callbacks module\n * @description Module works with editor added Elements\n *\n * @author Codex Team\n * @version 1.4.0\n */\n\nmodule.exports = (function (callbacks) {\n\n let editor = codex.editor;\n\n /**\n * used by UI module\n * @description Routes all keydowns on document\n * @param {Object} event\n */\n callbacks.globalKeydown = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.ENTER : enterKeyPressed_(event); break;\n }\n\n };\n\n /**\n * used by UI module\n * @description Routes all keydowns on redactors area\n * @param {Object} event\n */\n callbacks.redactorKeyDown = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.TAB : tabKeyPressedOnRedactorsZone_(event); break;\n case editor.core.keys.ENTER : enterKeyPressedOnRedactorsZone_(event); break;\n case editor.core.keys.ESC : escapeKeyPressedOnRedactorsZone_(event); break;\n default : defaultKeyPressedOnRedactorsZone_(event); break;\n }\n\n };\n\n /**\n * used by UI module\n * @description Routes all keyup events\n * @param {Object} event\n */\n callbacks.globalKeyup = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.UP :\n case editor.core.keys.LEFT :\n case editor.core.keys.RIGHT :\n case editor.core.keys.DOWN : arrowKeyPressed_(event); break;\n }\n\n };\n\n /**\n * @param {Object} event\n * @private\n *\n * Handles behaviour when tab pressed\n * @description if Content is empty show toolbox (if it is closed) or leaf tools\n * uses Toolbars toolbox module to handle the situation\n */\n var tabKeyPressedOnRedactorsZone_ = function (event) {\n\n /**\n * Wait for solution. Would like to know the behaviour\n * @todo Add spaces\n */\n event.preventDefault();\n\n\n if (!editor.core.isBlockEmpty(editor.content.currentNode)) {\n\n return;\n\n }\n\n if ( !editor.toolbar.opened ) {\n\n editor.toolbar.open();\n\n }\n\n if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\n editor.toolbar.toolbox.open();\n\n } else {\n\n editor.toolbar.toolbox.leaf();\n\n }\n\n };\n\n /**\n * Handles global EnterKey Press\n * @see enterPressedOnBlock_\n * @param {Object} event\n */\n var enterKeyPressed_ = function () {\n\n if (editor.content.editorAreaHightlighted) {\n\n /**\n * it means that we lose input index, saved index before is not correct\n * therefore we need to set caret when we insert new block\n */\n editor.caret.inputIndex = -1;\n\n enterPressedOnBlock_();\n\n }\n\n };\n\n /**\n * Callback for enter key pressing in first-level block area\n *\n * @param {Event} event\n * @private\n *\n * @description Inserts new block with initial type from settings\n */\n var enterPressedOnBlock_ = function () {\n\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render()\n }, true );\n\n editor.toolbar.move();\n editor.toolbar.open();\n\n };\n\n\n /**\n * ENTER key handler\n *\n * @param {Object} event\n * @private\n *\n * @description Makes new block with initial type from settings\n */\n var enterKeyPressedOnRedactorsZone_ = function (event) {\n\n if (event.target.contentEditable == 'true') {\n\n /** Update input index */\n editor.caret.saveCurrentInputIndex();\n\n }\n\n var currentInputIndex = editor.caret.getCurrentInputIndex() || 0,\n workingNode = editor.content.currentNode,\n tool = workingNode.dataset.tool,\n isEnterPressedOnToolbar = editor.toolbar.opened &&\n editor.toolbar.current &&\n event.target == editor.state.inputs[currentInputIndex];\n\n /** The list of tools which needs the default browser behaviour */\n var enableLineBreaks = editor.tools[tool].enableLineBreaks;\n\n /** This type of block creates when enter is pressed */\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n /**\n * When toolbar is opened, select tool instead of making new paragraph\n */\n if ( isEnterPressedOnToolbar ) {\n\n event.preventDefault();\n\n editor.toolbar.toolbox.toolClicked(event);\n\n editor.toolbar.close();\n\n /**\n * Stop other listeners callback executions\n */\n event.stopPropagation();\n event.stopImmediatePropagation();\n\n return;\n\n }\n\n /**\n * Allow paragraph lineBreaks with shift enter\n * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation\n */\n if ( event.shiftKey || enableLineBreaks ) {\n\n event.stopPropagation();\n event.stopImmediatePropagation();\n return;\n\n }\n\n var currentSelection = window.getSelection(),\n currentSelectedNode = currentSelection.anchorNode,\n caretAtTheEndOfText = editor.caret.position.atTheEnd(),\n isTextNodeHasParentBetweenContenteditable = false;\n\n /**\n * Allow making new <p> in same block by SHIFT+ENTER and forbids to prevent default browser behaviour\n */\n if ( event.shiftKey && !enableLineBreaks ) {\n\n editor.callback.enterPressedOnBlock(editor.content.currentBlock, event);\n event.preventDefault();\n return;\n\n }\n\n /**\n * Workaround situation when caret at the Text node that has some wrapper Elements\n * Split block cant handle this.\n * We need to save default behavior\n */\n isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true';\n\n /**\n * Split blocks when input has several nodes and caret placed in textNode\n */\n if (\n currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT &&\n !isTextNodeHasParentBetweenContenteditable &&\n !caretAtTheEndOfText\n ) {\n\n event.preventDefault();\n\n editor.core.log('Splitting Text node...');\n\n editor.content.splitBlock(currentInputIndex);\n\n /** Show plus button when next input after split is empty*/\n if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) {\n\n editor.toolbar.showPlusButton();\n\n }\n\n } else {\n\n var islastNode = editor.content.isLastNode(currentSelectedNode);\n\n if ( islastNode && caretAtTheEndOfText ) {\n\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n\n editor.core.log('ENTER clicked in last textNode. Create new BLOCK');\n\n editor.content.insertBlock({\n type: NEW_BLOCK_TYPE,\n block: editor.tools[NEW_BLOCK_TYPE].render()\n }, true);\n\n editor.toolbar.move();\n editor.toolbar.open();\n\n /** Show plus button with empty block */\n editor.toolbar.showPlusButton();\n\n }\n\n }\n\n /** get all inputs after new appending block */\n editor.ui.saveInputs();\n\n };\n\n /**\n * Escape behaviour\n * @param event\n * @private\n *\n * @description Closes toolbox and toolbar. Prevents default behaviour\n */\n var escapeKeyPressedOnRedactorsZone_ = function (event) {\n\n /** Close all toolbar */\n editor.toolbar.close();\n\n /** Close toolbox */\n editor.toolbar.toolbox.close();\n\n event.preventDefault();\n\n };\n\n /**\n * @param {Event} event\n * @private\n *\n * closes and moves toolbar\n */\n var arrowKeyPressed_ = function (event) {\n\n editor.content.workingNodeChanged();\n\n /* Closing toolbar */\n editor.toolbar.close();\n editor.toolbar.move();\n\n };\n\n /**\n * @private\n * @param {Event} event\n *\n * @description Closes all opened bars from toolbar.\n * If block is mark, clears highlightning\n */\n var defaultKeyPressedOnRedactorsZone_ = function () {\n\n editor.toolbar.close();\n\n if (!editor.toolbar.inline.actionsOpened) {\n\n editor.toolbar.inline.close();\n editor.content.clearMark();\n\n }\n\n };\n\n /**\n * Handler when clicked on redactors area\n *\n * @protected\n * @param event\n *\n * @description Detects clicked area. If it is first-level block area, marks as detected and\n * on next enter press will be inserted new block\n * Otherwise, save carets position (input index) and put caret to the editable zone.\n *\n * @see detectWhenClickedOnFirstLevelBlockArea_\n *\n */\n callbacks.redactorClicked = function (event) {\n\n detectWhenClickedOnFirstLevelBlockArea_();\n\n editor.content.workingNodeChanged(event.target);\n editor.ui.saveInputs();\n\n var selectedText = editor.toolbar.inline.getSelectionText(),\n firstLevelBlock;\n\n /** If selection range took off, then we hide inline toolbar */\n if (selectedText.length === 0) {\n\n editor.toolbar.inline.close();\n\n }\n\n /** Update current input index in memory when caret focused into existed input */\n if (event.target.contentEditable == 'true') {\n\n editor.caret.saveCurrentInputIndex();\n\n }\n\n if (editor.content.currentNode === null) {\n\n /**\n * If inputs in redactor does not exits, then we put input index 0 not -1\n */\n var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0;\n\n /** If we have any inputs */\n if (editor.state.inputs.length) {\n\n /** getting firstlevel parent of input */\n firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);\n\n }\n\n /** If input is empty, then we set caret to the last input */\n if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {\n\n editor.caret.setToBlock(indexOfLastInput);\n\n } else {\n\n /** Create new input when caret clicked in redactors area */\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render()\n });\n\n /** If there is no inputs except inserted */\n if (editor.state.inputs.length === 1) {\n\n editor.caret.setToBlock(indexOfLastInput);\n\n } else {\n\n /** Set caret to this appended input */\n editor.caret.setToNextBlock(indexOfLastInput);\n\n }\n\n }\n\n } else {\n\n /** Close all panels */\n editor.toolbar.settings.close();\n editor.toolbar.toolbox.close();\n\n }\n\n /**\n * Move toolbar and open\n */\n editor.toolbar.move();\n editor.toolbar.open();\n\n var inputIsEmpty = !editor.content.currentNode.textContent.trim(),\n currentNodeType = editor.content.currentNode.dataset.tool,\n isInitialType = currentNodeType == editor.settings.initialBlockPlugin;\n\n\n /** Hide plus buttons */\n editor.toolbar.hidePlusButton();\n\n if (!inputIsEmpty) {\n\n /** Mark current block */\n editor.content.markBlock();\n\n }\n\n if ( isInitialType && inputIsEmpty ) {\n\n /** Show plus button */\n editor.toolbar.showPlusButton();\n\n }\n\n\n };\n\n /**\n * This method allows to define, is caret in contenteditable element or not.\n *\n * @private\n *\n * @description Otherwise, if we get TEXT node from range container, that will means we have input index.\n * In this case we use default browsers behaviour (if plugin allows that) or overwritten action.\n * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always\n * specifies to the first-level block. Other cases we just ignore.\n */\n var detectWhenClickedOnFirstLevelBlockArea_ = function () {\n\n var selection = window.getSelection(),\n anchorNode = selection.anchorNode,\n flag = false;\n\n if (selection.rangeCount === 0) {\n\n editor.content.editorAreaHightlighted = true;\n\n } else {\n\n if (!editor.core.isDomNode(anchorNode)) {\n\n anchorNode = anchorNode.parentNode;\n\n }\n\n /** Already founded, without loop */\n if (anchorNode.contentEditable == 'true') {\n\n flag = true;\n\n }\n\n while (anchorNode.contentEditable != 'true') {\n\n anchorNode = anchorNode.parentNode;\n\n if (anchorNode.contentEditable == 'true') {\n\n flag = true;\n\n }\n\n if (anchorNode == document.body) {\n\n break;\n\n }\n\n }\n\n /** If editable element founded, flag is \"TRUE\", Therefore we return \"FALSE\" */\n editor.content.editorAreaHightlighted = !flag;\n\n }\n\n };\n\n /**\n * Toolbar button click handler\n *\n * @param {Object} event - cursor to the button\n * @protected\n *\n * @description gets current tool and calls render method\n */\n callbacks.toolbarButtonClicked = function (event) {\n\n var button = this;\n\n editor.toolbar.current = button.dataset.type;\n\n editor.toolbar.toolbox.toolClicked(event);\n editor.toolbar.close();\n\n };\n\n /**\n * Show or Hide toolbox when plus button is clicked\n */\n callbacks.plusButtonClicked = function () {\n\n if (!editor.nodes.toolbox.classList.contains('opened')) {\n\n editor.toolbar.toolbox.open();\n\n } else {\n\n editor.toolbar.toolbox.close();\n\n }\n\n };\n\n /**\n * Block handlers for KeyDown events\n *\n * @protected\n * @param {Object} event\n *\n * Handles keydowns on block\n * @see blockRightOrDownArrowPressed_\n * @see backspacePressed_\n * @see blockLeftOrUpArrowPressed_\n */\n callbacks.blockKeydown = function (event) {\n\n let block = event.target; // event.target is input\n\n switch (event.keyCode) {\n\n case editor.core.keys.DOWN:\n case editor.core.keys.RIGHT:\n blockRightOrDownArrowPressed_(event);\n break;\n\n case editor.core.keys.BACKSPACE:\n backspacePressed_(block, event);\n break;\n\n case editor.core.keys.UP:\n case editor.core.keys.LEFT:\n blockLeftOrUpArrowPressed_(event);\n break;\n\n }\n\n };\n\n /**\n * RIGHT or DOWN keydowns on block\n *\n * @param {Object} event\n * @private\n *\n * @description watches the selection and gets closest editable element.\n * Uses method getDeepestTextNodeFromPosition to get the last node of next block\n * Sets caret if it is contenteditable\n */\n var blockRightOrDownArrowPressed_ = function (event) {\n\n var selection = window.getSelection(),\n inputs = editor.state.inputs,\n focusedNode = selection.anchorNode,\n focusedNodeHolder;\n\n /** Check for caret existance */\n if (!focusedNode) {\n\n return false;\n\n }\n\n /** Looking for closest (parent) contentEditable element of focused node */\n while (focusedNode.contentEditable != 'true') {\n\n focusedNodeHolder = focusedNode.parentNode;\n focusedNode = focusedNodeHolder;\n\n }\n\n /** Input index in DOM level */\n var editableElementIndex = 0;\n\n while (focusedNode != inputs[editableElementIndex]) {\n\n editableElementIndex ++;\n\n }\n\n /**\n * Founded contentEditable element doesn't have childs\n * Or maybe New created block\n */\n if (!focusedNode.textContent) {\n\n editor.caret.setToNextBlock(editableElementIndex);\n return;\n\n }\n\n /**\n * Do nothing when caret doesn not reaches the end of last child\n */\n var caretInLastChild = false,\n caretAtTheEndOfText = false;\n\n var lastChild,\n deepestTextnode;\n\n lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1 ];\n\n if (editor.core.isDomNode(lastChild)) {\n\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length);\n\n } else {\n\n deepestTextnode = lastChild;\n\n }\n\n caretInLastChild = selection.anchorNode == deepestTextnode;\n caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset;\n\n if ( !caretInLastChild || !caretAtTheEndOfText ) {\n\n editor.core.log('arrow [down|right] : caret does not reached the end');\n return false;\n\n }\n\n editor.caret.setToNextBlock(editableElementIndex);\n\n };\n\n /**\n * LEFT or UP keydowns on block\n *\n * @param {Object} event\n * @private\n *\n * watches the selection and gets closest editable element.\n * Uses method getDeepestTextNodeFromPosition to get the last node of previous block\n * Sets caret if it is contenteditable\n *\n */\n var blockLeftOrUpArrowPressed_ = function (event) {\n\n var selection = window.getSelection(),\n inputs = editor.state.inputs,\n focusedNode = selection.anchorNode,\n focusedNodeHolder;\n\n /** Check for caret existance */\n if (!focusedNode) {\n\n return false;\n\n }\n\n /**\n * LEFT or UP not at the beginning\n */\n if ( selection.anchorOffset !== 0) {\n\n return false;\n\n }\n\n /** Looking for parent contentEditable block */\n while (focusedNode.contentEditable != 'true') {\n\n focusedNodeHolder = focusedNode.parentNode;\n focusedNode = focusedNodeHolder;\n\n }\n\n /** Input index in DOM level */\n var editableElementIndex = 0;\n\n while (focusedNode != inputs[editableElementIndex]) {\n\n editableElementIndex ++;\n\n }\n\n /**\n * Do nothing if caret is not at the beginning of first child\n */\n var caretInFirstChild = false,\n caretAtTheBeginning = false;\n\n var firstChild,\n deepestTextnode;\n\n /**\n * Founded contentEditable element doesn't have childs\n * Or maybe New created block\n */\n if (!focusedNode.textContent) {\n\n editor.caret.setToPreviousBlock(editableElementIndex);\n return;\n\n }\n\n firstChild = focusedNode.childNodes[0];\n\n if (editor.core.isDomNode(firstChild)) {\n\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0);\n\n } else {\n\n deepestTextnode = firstChild;\n\n }\n\n caretInFirstChild = selection.anchorNode == deepestTextnode;\n caretAtTheBeginning = selection.anchorOffset === 0;\n\n if ( caretInFirstChild && caretAtTheBeginning ) {\n\n editor.caret.setToPreviousBlock(editableElementIndex);\n\n }\n\n };\n\n /**\n * Handles backspace keydown\n *\n * @param {Element} block\n * @param {Object} event\n * @private\n *\n * @description if block is empty, delete the block and set caret to the previous block\n * If block is not empty, try to merge two blocks - current and previous\n * But it we try'n to remove first block, then we should set caret to the next block, not previous.\n * If we removed the last block, create new one\n */\n var backspacePressed_ = function (block, event) {\n\n var currentInputIndex = editor.caret.getCurrentInputIndex(),\n range,\n selectionLength,\n firstLevelBlocksCount;\n\n if (editor.core.isNativeInput(event.target)) {\n\n /** If input value is empty - remove block */\n if (event.target.value.trim() == '') {\n\n block.remove();\n\n } else {\n\n return;\n\n }\n\n }\n\n if (block.textContent.trim()) {\n\n range = editor.content.getRange();\n selectionLength = range.endOffset - range.startOffset;\n\n if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {\n\n editor.content.mergeBlocks(currentInputIndex);\n\n } else {\n\n return;\n\n }\n\n }\n\n if (!selectionLength) {\n\n block.remove();\n\n }\n\n\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\n /**\n * If all blocks are removed\n */\n if (firstLevelBlocksCount === 0) {\n\n /** update currentNode variable */\n editor.content.currentNode = null;\n\n /** Inserting new empty initial block */\n editor.ui.addInitialBlock();\n\n /** Updating inputs state after deleting last block */\n editor.ui.saveInputs();\n\n /** Set to current appended block */\n window.setTimeout(function () {\n\n editor.caret.setToPreviousBlock(1);\n\n }, 10);\n\n } else {\n\n if (editor.caret.inputIndex !== 0) {\n\n /** Target block is not first */\n editor.caret.setToPreviousBlock(editor.caret.inputIndex);\n\n } else {\n\n /** If we try to delete first block */\n editor.caret.setToNextBlock(editor.caret.inputIndex);\n\n }\n\n }\n\n editor.toolbar.move();\n\n if (!editor.toolbar.opened) {\n\n editor.toolbar.open();\n\n }\n\n /** Updating inputs state */\n editor.ui.saveInputs();\n\n /** Prevent default browser behaviour */\n event.preventDefault();\n\n };\n\n /**\n * used by UI module\n * Clicks on block settings button\n *\n * @param {Object} event\n * @protected\n * @description Opens toolbar settings\n */\n callbacks.showSettingsButtonClicked = function (event) {\n\n /**\n * Get type of current block\n * It uses to append settings from tool.settings property.\n * ...\n * Type is stored in data-type attribute on block\n */\n var currentToolType = editor.content.currentNode.dataset.tool;\n\n editor.toolbar.settings.toggle(currentToolType);\n\n /** Close toolbox when settings button is active */\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.hideRemoveActions();\n\n };\n\n return callbacks;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/callbacks.js","/**\n * Codex Editor Draw module\n *\n * @author Codex Team\n * @version 1.0.\n */\n\nmodule.exports = (function (draw) {\n\n /**\n * Base editor wrapper\n */\n draw.wrapper = function () {\n\n var wrapper = document.createElement('div');\n\n wrapper.className += 'codex-editor';\n\n return wrapper;\n\n };\n\n /**\n * Content-editable holder\n */\n draw.redactor = function () {\n\n var redactor = document.createElement('div');\n\n redactor.className += 'ce-redactor';\n\n return redactor;\n\n };\n\n draw.ceBlock = function () {\n\n var block = document.createElement('DIV');\n\n block.className += 'ce_block';\n\n return block;\n\n };\n\n /**\n * Empty toolbar with toggler\n */\n draw.toolbar = function () {\n\n var bar = document.createElement('div');\n\n bar.className += 'ce-toolbar';\n\n return bar;\n\n };\n\n draw.toolbarContent = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.classList.add('ce-toolbar__content');\n\n return wrapper;\n\n };\n\n /**\n * Inline toolbar\n */\n draw.inlineToolbar = function () {\n\n var bar = document.createElement('DIV');\n\n bar.className += 'ce-toolbar-inline';\n\n return bar;\n\n };\n\n /**\n * Wrapper for inline toobar buttons\n */\n draw.inlineToolbarButtons = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.className += 'ce-toolbar-inline__buttons';\n\n return wrapper;\n\n };\n\n /**\n * For some actions\n */\n draw.inlineToolbarActions = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.className += 'ce-toolbar-inline__actions';\n\n return wrapper;\n\n };\n\n draw.inputForLink = function () {\n\n var input = document.createElement('INPUT');\n\n input.type = 'input';\n input.className += 'inputForLink';\n input.placeholder = 'Вставьте ссылку ...';\n input.setAttribute('form', 'defaultForm');\n\n input.setAttribute('autofocus', 'autofocus');\n\n return input;\n\n };\n\n /**\n * @todo Desc\n */\n draw.blockButtons = function () {\n\n var block = document.createElement('div');\n\n block.className += 'ce-toolbar__actions';\n\n return block;\n\n };\n\n /**\n * Block settings panel\n */\n draw.blockSettings = function () {\n\n var settings = document.createElement('div');\n\n settings.className += 'ce-settings';\n\n return settings;\n\n };\n\n draw.defaultSettings = function () {\n\n var div = document.createElement('div');\n\n div.classList.add('ce-settings_default');\n\n return div;\n\n };\n\n draw.pluginsSettings = function () {\n\n var div = document.createElement('div');\n\n div.classList.add('ce-settings_plugin');\n\n return div;\n\n };\n\n draw.plusButton = function () {\n\n var button = document.createElement('span');\n\n button.className = 'ce-toolbar__plus';\n // button.innerHTML = '<i class=\"ce-icon-plus\"></i>';\n\n return button;\n\n };\n\n /**\n * Settings button in toolbar\n */\n draw.settingsButton = function () {\n\n var toggler = document.createElement('span');\n\n toggler.className = 'ce-toolbar__settings-btn';\n\n /** Toggler button*/\n toggler.innerHTML = '<i class=\"ce-icon-cog\"></i>';\n\n return toggler;\n\n };\n\n /**\n * Redactor tools wrapper\n */\n\n draw.toolbox = function () {\n\n var wrapper = document.createElement('div');\n\n wrapper.className = 'ce-toolbar__tools';\n\n return wrapper;\n\n };\n\n /**\n * @protected\n *\n * Draws tool buttons for toolbox\n *\n * @param {String} type\n * @param {String} classname\n * @returns {Element}\n */\n draw.toolbarButton = function (type, classname) {\n\n var button = document.createElement('li'),\n toolIcon = document.createElement('i'),\n toolTitle = document.createElement('span');\n\n button.dataset.type = type;\n button.setAttribute('title', type);\n\n toolIcon.classList.add(classname);\n toolTitle.classList.add('ce_toolbar_tools--title');\n\n\n button.appendChild(toolIcon);\n button.appendChild(toolTitle);\n\n return button;\n\n };\n\n /**\n * @protected\n *\n * Draws tools for inline toolbar\n *\n * @param {String} type\n * @param {String} classname\n */\n draw.toolbarButtonInline = function (type, classname) {\n\n var button = document.createElement('BUTTON'),\n toolIcon = document.createElement('I');\n\n button.type = 'button';\n button.dataset.type = type;\n toolIcon.classList.add(classname);\n\n button.appendChild(toolIcon);\n\n return button;\n\n };\n\n /**\n * Redactor block\n */\n draw.block = function (tagName, content) {\n\n var node = document.createElement(tagName);\n\n node.innerHTML = content || '';\n\n return node;\n\n };\n\n /**\n * Creates Node with passed tagName and className\n * @param {string} tagName\n * @param {string} className\n * @param {object} properties - allow to assign properties\n */\n draw.node = function ( tagName, className, properties ) {\n\n var el = document.createElement( tagName );\n\n if ( className ) el.className = className;\n\n if ( properties ) {\n\n for (var name in properties) {\n\n el[name] = properties[name];\n\n }\n\n }\n\n return el;\n\n };\n\n /**\n * Unavailable plugin block\n */\n draw.unavailableBlock = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.classList.add('cdx-unavailable-block');\n\n return wrapper;\n\n };\n\n return draw;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/draw.js","/**\n * Codex Editor Caret Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (caret) {\n\n let editor = codex.editor;\n\n /**\n * @var {int} InputIndex - editable element in DOM\n */\n caret.inputIndex = null;\n\n /**\n * @var {int} offset - caret position in a text node.\n */\n caret.offset = null;\n\n /**\n * @var {int} focusedNodeIndex - we get index of child node from first-level block\n */\n caret.focusedNodeIndex = null;\n\n /**\n * Creates Document Range and sets caret to the element.\n * @protected\n * @uses caret.save — if you need to save caret position\n * @param {Element} el - Changed Node.\n */\n caret.set = function ( el, index, offset) {\n\n offset = offset || caret.offset || 0;\n index = index || caret.focusedNodeIndex || 0;\n\n var childs = el.childNodes,\n nodeToSet;\n\n if ( childs.length === 0 ) {\n\n nodeToSet = el;\n\n } else {\n\n nodeToSet = childs[index];\n\n }\n\n /** If Element is INPUT */\n if (el.contentEditable != 'true') {\n\n el.focus();\n return;\n\n }\n\n if (editor.core.isDomNode(nodeToSet)) {\n\n nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);\n\n }\n\n var range = document.createRange(),\n selection = window.getSelection();\n\n window.setTimeout(function () {\n\n range.setStart(nodeToSet, offset);\n range.setEnd(nodeToSet, offset);\n\n selection.removeAllRanges();\n selection.addRange(range);\n\n editor.caret.saveCurrentInputIndex();\n\n }, 20);\n\n };\n\n /**\n * @protected\n * Updates index of input and saves it in caret object\n */\n caret.saveCurrentInputIndex = function () {\n\n /** Index of Input that we paste sanitized content */\n var selection = window.getSelection(),\n inputs = editor.state.inputs,\n focusedNode = selection.anchorNode,\n focusedNodeHolder;\n\n if (!focusedNode) {\n\n return;\n\n }\n\n /** Looking for parent contentEditable block */\n while (focusedNode && focusedNode.contentEditable != 'true') {\n\n focusedNodeHolder = focusedNode.parentNode;\n focusedNode = focusedNodeHolder;\n\n }\n\n /** Input index in DOM level */\n var editableElementIndex = 0;\n\n while (focusedNode != inputs[editableElementIndex]) {\n\n editableElementIndex ++;\n\n }\n\n caret.inputIndex = editableElementIndex;\n\n };\n\n /**\n * Returns current input index (caret object)\n */\n caret.getCurrentInputIndex = function () {\n\n return caret.inputIndex;\n\n };\n\n /**\n * @param {int} index - index of first-level block after that we set caret into next input\n */\n caret.setToNextBlock = function (index) {\n\n var inputs = editor.state.inputs,\n nextInput = inputs[index + 1];\n\n if (!nextInput) {\n\n editor.core.log('We are reached the end');\n return;\n\n }\n\n /**\n * When new Block created or deleted content of input\n * We should add some text node to set caret\n */\n if (!nextInput.childNodes.length) {\n\n var emptyTextElement = document.createTextNode('');\n\n nextInput.appendChild(emptyTextElement);\n\n }\n\n editor.caret.inputIndex = index + 1;\n editor.caret.set(nextInput, 0, 0);\n editor.content.workingNodeChanged(nextInput);\n\n };\n\n /**\n * @param {int} index - index of target input.\n * Sets caret to input with this index\n */\n caret.setToBlock = function (index) {\n\n var inputs = editor.state.inputs,\n targetInput = inputs[index];\n\n if ( !targetInput ) {\n\n return;\n\n }\n\n /**\n * When new Block created or deleted content of input\n * We should add some text node to set caret\n */\n if (!targetInput.childNodes.length) {\n\n var emptyTextElement = document.createTextNode('');\n\n targetInput.appendChild(emptyTextElement);\n\n }\n\n editor.caret.inputIndex = index;\n editor.caret.set(targetInput, 0, 0);\n editor.content.workingNodeChanged(targetInput);\n\n };\n\n /**\n * @param {int} index - index of input\n */\n caret.setToPreviousBlock = function (index) {\n\n index = index || 0;\n\n var inputs = editor.state.inputs,\n previousInput = inputs[index - 1],\n lastChildNode,\n lengthOfLastChildNode,\n emptyTextElement;\n\n\n if (!previousInput) {\n\n editor.core.log('We are reached first node');\n return;\n\n }\n\n lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length);\n lengthOfLastChildNode = lastChildNode.length;\n\n /**\n * When new Block created or deleted content of input\n * We should add some text node to set caret\n */\n if (!previousInput.childNodes.length) {\n\n emptyTextElement = document.createTextNode('');\n previousInput.appendChild(emptyTextElement);\n\n }\n editor.caret.inputIndex = index - 1;\n editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode);\n editor.content.workingNodeChanged(inputs[index - 1]);\n\n };\n\n caret.position = {\n\n atStart : function () {\n\n var selection = window.getSelection(),\n anchorOffset = selection.anchorOffset,\n anchorNode = selection.anchorNode,\n firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode),\n pluginsRender = firstLevelBlock.childNodes[0];\n\n if (!editor.core.isDomNode(anchorNode)) {\n\n anchorNode = anchorNode.parentNode;\n\n }\n\n var isFirstNode = anchorNode === pluginsRender.childNodes[0],\n isOffsetZero = anchorOffset === 0;\n\n return isFirstNode && isOffsetZero;\n\n },\n\n atTheEnd : function () {\n\n var selection = window.getSelection(),\n anchorOffset = selection.anchorOffset,\n anchorNode = selection.anchorNode;\n\n /** Caret is at the end of input */\n return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length;\n\n }\n };\n\n\n /**\n * Inserts node at the caret location\n * @param {HTMLElement|DocumentFragment} node\n */\n caret.insertNode = function (node) {\n\n var selection, range,\n lastNode = node;\n\n if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) {\n\n lastNode = node.lastChild;\n\n }\n\n selection = window.getSelection();\n\n range = selection.getRangeAt(0);\n range.deleteContents();\n\n range.insertNode(node);\n\n range.setStartAfter(lastNode);\n range.collapse(true);\n\n selection.removeAllRanges();\n selection.addRange(range);\n\n\n };\n\n return caret;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/caret.js","/**\n * Codex Editor Notification Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (notifications) {\n\n let editor = codex.editor;\n\n var queue = [];\n\n var addToQueue = function (settings) {\n\n queue.push(settings);\n\n var index = 0;\n\n while ( index < queue.length && queue.length > 5) {\n\n if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n\n index++;\n continue;\n\n }\n\n queue[index].close();\n queue.splice(index, 1);\n\n }\n\n };\n\n notifications.createHolder = function () {\n\n var holder = editor.draw.node('DIV', 'cdx-notifications-block');\n\n editor.nodes.notifications = document.body.appendChild(holder);\n\n return holder;\n\n };\n\n\n /**\n * Error notificator. Shows block with message\n * @protected\n */\n notifications.errorThrown = function (errorMsg, event) {\n\n editor.notifications.notification({message: 'This action is not available currently', type: event.type});\n\n };\n\n /**\n *\n * Appends notification\n *\n * settings = {\n * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\n * message - notification message\n * okMsg - confirm button text (default - 'Ok')\n * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\n * confirm - function-handler for ok button click\n * cancel - function-handler for cancel button click. Only for confirm and prompt types\n * time - time (in seconds) after which notification will close (default - 10s)\n * }\n *\n * @param settings\n */\n notifications.notification = function (constructorSettings) {\n\n /** Private vars and methods */\n var notification = null,\n cancel = null,\n type = null,\n confirm = null,\n inputField = null;\n\n var confirmHandler = function () {\n\n close();\n\n if (typeof confirm !== 'function' ) {\n\n return;\n\n }\n\n if (type == 'prompt') {\n\n confirm(inputField.value);\n return;\n\n }\n\n confirm();\n\n };\n\n var cancelHandler = function () {\n\n close();\n\n if (typeof cancel !== 'function' ) {\n\n return;\n\n }\n\n cancel();\n\n };\n\n\n /** Public methods */\n function create(settings) {\n\n if (!(settings && settings.message)) {\n\n editor.core.log('Can\\'t create notification. Message is missed');\n return;\n\n }\n\n settings.type = settings.type || 'alert';\n settings.time = settings.time*1000 || 10000;\n\n var wrapper = editor.draw.node('DIV', 'cdx-notification'),\n message = editor.draw.node('DIV', 'cdx-notification__message'),\n input = editor.draw.node('INPUT', 'cdx-notification__input'),\n okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\n cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\n\n message.textContent = settings.message;\n okBtn.textContent = settings.okMsg || 'ОК';\n cancelBtn.textContent = settings.cancelMsg || 'Отмена';\n\n editor.listeners.add(okBtn, 'click', confirmHandler);\n editor.listeners.add(cancelBtn, 'click', cancelHandler);\n\n wrapper.appendChild(message);\n\n if (settings.type == 'prompt') {\n\n wrapper.appendChild(input);\n\n }\n\n wrapper.appendChild(okBtn);\n\n if (settings.type == 'prompt' || settings.type == 'confirm') {\n\n wrapper.appendChild(cancelBtn);\n\n }\n\n wrapper.classList.add('cdx-notification-' + settings.type);\n wrapper.dataset.type = settings.type;\n\n notification = wrapper;\n type = settings.type;\n confirm = settings.confirm;\n cancel = settings.cancel;\n inputField = input;\n\n if (settings.type != 'prompt' && settings.type != 'confirm') {\n\n window.setTimeout(close, settings.time);\n\n }\n\n };\n\n /**\n * Show notification block\n */\n function send() {\n\n editor.nodes.notifications.appendChild(notification);\n inputField.focus();\n\n editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\n\n window.setTimeout(function () {\n\n editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n\n }, 100);\n\n addToQueue({type: type, close: close});\n\n };\n\n /**\n * Remove notification block\n */\n function close() {\n\n notification.remove();\n\n };\n\n\n if (constructorSettings) {\n\n create(constructorSettings);\n send();\n\n }\n\n return {\n create: create,\n send: send,\n close: close\n };\n\n };\n\n notifications.clear = function () {\n\n editor.nodes.notifications.innerHTML = '';\n queue = [];\n\n };\n\n return notifications;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/notifications.js","/**\n * Codex Editor Parser Module\n *\n * @author Codex Team\n * @version 1.1\n */\n\nmodule.exports = (function (parser) {\n\n let editor = codex.editor;\n\n /** inserting text */\n parser.insertPastedContent = function (blockType, tag) {\n\n editor.content.insertBlock({\n type : blockType.type,\n block : blockType.render({\n text : tag.innerHTML\n })\n });\n\n };\n\n /**\n * Check DOM node for display style: separated block or child-view\n */\n parser.isFirstLevelBlock = function (node) {\n\n return node.nodeType == editor.core.nodeTypes.TAG &&\n node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n\n };\n\n return parser;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/parser.js","/**\n * Codex Sanitizer\n */\n\nmodule.exports = (function (sanitizer) {\n\n /** HTML Janitor library */\n let janitor = require('html-janitor');\n\n /** Codex Editor */\n let editor = codex.editor;\n\n sanitizer.prepare = function () {\n\n if (editor.settings.sanitizer && !editor.core.isEmpty(editor.settings.sanitizer)) {\n\n Config.CUSTOM = editor.settings.sanitizer;\n\n }\n\n };\n\n /**\n * Basic config\n */\n var Config = {\n\n /** User configuration */\n CUSTOM : null,\n\n BASIC : {\n\n tags: {\n p: {},\n a: {\n href: true,\n target: '_blank',\n rel: 'nofollow'\n }\n }\n }\n };\n\n sanitizer.Config = Config;\n\n /**\n *\n * @param userCustomConfig\n * @returns {*}\n * @private\n *\n * @description If developer uses editor's API, then he can customize sane restrictions.\n * Or, sane config can be defined globally in editors initialization. That config will be used everywhere\n * At least, if there is no config overrides, that API uses BASIC Default configation\n */\n let init_ = function (userCustomConfig) {\n\n let configuration = userCustomConfig || Config.CUSTOM || Config.BASIC;\n\n return new janitor(configuration);\n\n };\n\n /**\n * Cleans string from unwanted tags\n * @protected\n * @param {String} dirtyString - taint string\n * @param {Object} customConfig - allowed tags\n */\n sanitizer.clean = function (dirtyString, customConfig) {\n\n let janitorInstance = init_(customConfig);\n\n return janitorInstance.clean(dirtyString);\n\n };\n\n return sanitizer;\n\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","/**\n * Codex Editor Listeners module\n *\n * @author Codex Team\n * @version 1.0\n */\n\n/**\n * Module-decorator for event listeners assignment\n */\nmodule.exports = function (listeners) {\n\n var allListeners = [];\n\n /**\n * Search methods\n *\n * byElement, byType and byHandler returns array of suitable listeners\n * one and all takes element, eventType, and handler and returns first (all) suitable listener\n *\n */\n listeners.search = function () {\n\n var byElement = function (element, context) {\n\n var listenersOnElement = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.element === element) {\n\n listenersOnElement.push(listener);\n\n }\n\n }\n\n return listenersOnElement;\n\n };\n\n var byType = function (eventType, context) {\n\n var listenersWithType = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.type === eventType) {\n\n listenersWithType.push(listener);\n\n }\n\n }\n\n return listenersWithType;\n\n };\n\n var byHandler = function (handler, context) {\n\n var listenersWithHandler = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.handler === handler) {\n\n listenersWithHandler.push(listener);\n\n }\n\n }\n\n return listenersWithHandler;\n\n };\n\n var one = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result[0];\n\n };\n\n var all = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result;\n\n };\n\n return {\n byElement : byElement,\n byType : byType,\n byHandler : byHandler,\n one : one,\n all : all\n };\n\n }();\n\n listeners.add = function (element, eventType, handler, isCapture) {\n\n element.addEventListener(eventType, handler, isCapture);\n\n var data = {\n element: element,\n type: eventType,\n handler: handler\n };\n\n var alreadyAddedListener = listeners.search.one(element, eventType, handler);\n\n if (!alreadyAddedListener) {\n\n allListeners.push(data);\n\n }\n\n };\n\n listeners.remove = function (element, eventType, handler) {\n\n element.removeEventListener(eventType, handler);\n\n var existingListeners = listeners.search.all(element, eventType, handler);\n\n for (var i = 0; i < existingListeners.length; i++) {\n\n var index = allListeners.indexOf(existingListeners[i]);\n\n if (index > 0) {\n\n allListeners.splice(index, 1);\n\n }\n\n }\n\n };\n\n listeners.removeAll = function () {\n\n allListeners.map(function (current) {\n\n listeners.remove(current.element, current.type, current.handler);\n\n });\n\n };\n\n listeners.get = function (element, eventType, handler) {\n\n return listeners.search.all(element, eventType, handler);\n\n };\n\n return listeners;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/listeners.js","/**\n * Codex Editor Destroyer module\n *\n * @auhor Codex Team\n * @version 1.0\n */\n\nmodule.exports = function (destroyer) {\n\n let editor = codex.editor;\n\n destroyer.removeNodes = function () {\n\n editor.nodes.wrapper.remove();\n editor.nodes.notifications.remove();\n\n };\n\n destroyer.destroyPlugins = function () {\n\n for (var tool in editor.tools) {\n\n if (typeof editor.tools[tool].destroy === 'function') {\n\n editor.tools[tool].destroy();\n\n }\n\n }\n\n };\n\n destroyer.destroyScripts = function () {\n\n var scripts = document.getElementsByTagName('SCRIPT');\n\n for (var i = 0; i < scripts.length; i++) {\n\n if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n\n scripts[i].remove();\n i--;\n\n }\n\n }\n\n };\n\n\n /**\n * Delete editor data from webpage.\n * You should send settings argument with boolean flags:\n * @param settings.ui- remove redactor event listeners and DOM nodes\n * @param settings.scripts - remove redactor scripts from DOM\n * @param settings.plugins - remove plugin's objects\n * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\n * }\n *\n */\n destroyer.destroy = function (settings) {\n\n if (!settings || typeof settings !== 'object') {\n\n return;\n\n }\n\n if (settings.ui) {\n\n destroyer.removeNodes();\n editor.listeners.removeAll();\n\n }\n\n if (settings.scripts) {\n\n destroyer.destroyScripts();\n\n }\n\n if (settings.plugins) {\n\n destroyer.destroyPlugins();\n\n }\n\n if (settings.ui && settings.scripts && settings.core) {\n\n delete codex.editor;\n\n }\n\n };\n\n return destroyer;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/destroyer.js","/**\n * Codex Editor Paste module\n *\n * @author Codex Team\n * @version 1.1.1\n */\n\nmodule.exports = function (paste) {\n\n let editor = codex.editor;\n\n var patterns = [];\n\n paste.prepare = function () {\n\n var tools = editor.tools;\n\n for (var tool in tools) {\n\n if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n\n continue;\n\n }\n\n tools[tool].renderOnPastePatterns.map(function (pattern) {\n\n\n patterns.push(pattern);\n\n });\n\n }\n\n return Promise.resolve();\n\n };\n\n /**\n * Saves data\n * @param event\n */\n paste.pasted = function (event) {\n\n var clipBoardData = event.clipboardData || window.clipboardData,\n content = clipBoardData.getData('Text');\n\n var result = analize(content);\n\n if (result) {\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n }\n\n return result;\n\n };\n\n /**\n * Analizes pated string and calls necessary method\n */\n\n var analize = function (string) {\n\n var result = false,\n content = editor.content.currentNode,\n plugin = content.dataset.tool;\n\n patterns.map( function (pattern) {\n\n var execArray = pattern.regex.exec(string),\n match = execArray && execArray[0];\n\n if ( match && match === string.trim()) {\n\n /** current block is not empty */\n if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {\n\n pasteToNewBlock_();\n\n }\n\n pattern.callback(string, pattern);\n result = true;\n\n }\n\n });\n\n return result;\n\n };\n\n var pasteToNewBlock_ = function () {\n\n /** Create new initial block */\n editor.content.insertBlock({\n\n type : editor.settings.initialBlockPlugin,\n block : editor.tools[editor.settings.initialBlockPlugin].render({\n text : ''\n })\n\n }, false);\n\n };\n\n /**\n * This method prevents default behaviour.\n *\n * @param {Object} event\n * @protected\n *\n * @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.\n * Firstly, we need to memorize the caret position. We can do that by getting the range of selection.\n * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node\n */\n paste.blockPasteCallback = function (event) {\n\n\n if (!needsToHandlePasteEvent(event.target)) {\n\n return;\n\n }\n\n /** Prevent default behaviour */\n event.preventDefault();\n\n /** get html pasted data - dirty data */\n var htmlData = event.clipboardData.getData('text/html'),\n plainData = event.clipboardData.getData('text/plain');\n\n /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/\n var paragraphs = editor.draw.node('DIV', '', {}),\n cleanData,\n wrappedData;\n\n /** Create fragment, that we paste to range after proccesing */\n cleanData = editor.sanitizer.clean(htmlData);\n\n /**\n * We wrap pasted text with <p> tags to split it logically\n * @type {string}\n */\n wrappedData = editor.content.wrapTextWithParagraphs(cleanData, plainData);\n paragraphs.innerHTML = wrappedData;\n\n /**\n * If there only one paragraph, just insert in at the caret location\n */\n if (paragraphs.childNodes.length == 1) {\n\n emulateUserAgentBehaviour(paragraphs.firstChild);\n return;\n\n }\n\n insertPastedParagraphs(paragraphs.childNodes);\n\n };\n\n /**\n * Checks if we should handle paste event on block\n * @param block\n *\n * @return {boolean}\n */\n var needsToHandlePasteEvent = function (block) {\n\n /** If area is input or textarea then allow default behaviour */\n if ( editor.core.isNativeInput(block) ) {\n\n return false;\n\n }\n\n var editableParent = editor.content.getEditableParent(block);\n\n /** Allow paste when event target placed in Editable element */\n if (!editableParent) {\n\n return false;\n\n }\n\n return true;\n\n };\n\n /**\n * Inserts new initial plugin blocks with data in paragraphs\n *\n * @param {Array} paragraphs - array of paragraphs (<p></p>) whit content, that should be inserted\n */\n var insertPastedParagraphs = function (paragraphs) {\n\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin,\n currentNode = editor.content.currentNode;\n\n\n paragraphs.forEach(function (paragraph) {\n\n /** Don't allow empty paragraphs */\n if (editor.core.isBlockEmpty(paragraph)) {\n\n return;\n\n }\n\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render({\n text : paragraph.innerHTML\n })\n });\n\n editor.caret.inputIndex++;\n\n });\n\n editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1);\n\n\n /**\n * If there was no data in working node, remove it\n */\n if (editor.core.isBlockEmpty(currentNode)) {\n\n currentNode.remove();\n editor.ui.saveInputs();\n\n }\n\n\n };\n\n /**\n * Inserts node content at the caret position\n *\n * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location\n */\n var emulateUserAgentBehaviour = function (node) {\n\n var newNode;\n\n if (node.childElementCount) {\n\n newNode = document.createDocumentFragment();\n\n node.childNodes.forEach(function (current) {\n\n if (!editor.core.isDomNode(current) && current.data.trim() === '') {\n\n return;\n\n }\n\n newNode.appendChild(current.cloneNode(true));\n\n });\n\n } else {\n\n newNode = document.createTextNode(node.textContent);\n\n }\n\n editor.caret.insertNode(newNode);\n\n };\n\n\n return paste;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/paste.js"],"sourceRoot":""}