mirror of
https://github.com/codex-team/editor.js
synced 2024-06-20 14:45:07 +02:00
1397727115
* paste module improvements * paste callback improved users won’t be able to paste on block without designMode
1 line
316 KiB
Plaintext
1 line
316 KiB
Plaintext
{"version":3,"sources":["webpack:///codex-editor.js","webpack:///webpack/bootstrap 43045d00c4b3573b3ca6","webpack:///./codex.js","webpack:///./modules/core.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"],"names":["codex","modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","editor","version","init","core","ui","transport","renderer","saver","content","toolbar","callback","draw","caret","notifications","parser","sanitizer","settings","tools","textareaId","uploadImagesUrl","initialBlockPlugin","nodes","textarea","wrapper","inlineToolbar","buttons","actions","toolbox","plusButton","showSettingsButton","showTrashButton","blockSettings","pluginSettings","defaultSettings","toolbarButtons","redactor","state","jsonOutput","blocks","inputs","start","userSettings","prepare","then","make","addTools","bindEvents","preparePlugins","makeBlocksFromData","saveInputs","catch","error","log","_typeof","Symbol","iterator","obj","constructor","prototype","Promise","resolve","reject","data","document","getElementById","undefined","Error","msg","type","arg","window","console","e","insertAfter","target","element","parentNode","insertBefore","nextSibling","nodeTypes","TAG","TEXT","COMMENT","keys","BACKSPACE","TAB","ENTER","SHIFT","CTRL","ALT","ESC","SPACE","LEFT","UP","DOWN","RIGHT","DELETE","META","isDomNode","el","nodeType","this","ajax","url","XMLHTTP","XMLHttpRequest","ActiveXObject","successFunction","params","async","success","test","encodeURIComponent","withCredentials","beforeSend","open","setRequestHeader","onreadystatechange","readyState","status","responseText","send","importScript","scriptPath","instanceName","instancePrefix","script","createElement","defer","onload","onerror","src","head","appendChild","className","BLOCK_CLASSNAME","BLOCK_CONTENT","BLOCK_STRETCHED","BLOCK_HIGHLIGHTED","BLOCK_IN_FEED_MODE","SETTINGS_ITEM","toolbarContent","blockButtons","alertsHolder","body","settingsButton","makeRemoveBlockButton","pluginsSettings","makeInlineToolbar","addDefaultSettings","container","inlineToolbarButtons","inlineToolbarActions","tool","toolName","toolButton","iconClassname","render","displayInToolbox","toolbarButton","addInlineToolbarTools","bold","icon","command","italic","underline","link","name","toolbarButtonInline","setInlineToolbarButtonBehaviour","addEventListener","globalKeydown","redactorKeyDown","globalKeyup","redactorClicked","plusButtonClicked","showSettingsButtonClicked","button","toolbarButtonClicked","pluginName","plugin","config","addBlockHandlers","block","blockKeydown","blockPasteCallback","inline","show","querySelectorAll","addInitialBlock","initialBlock","initialBlockType","setAttribute","insertBlock","workingNodeChanged","event","toolClicked","input","arguments","fileSelected","clearInput","files","formdData","FormData","append","selectAndUpload","args","click","xhr","items","length","appendBlocks","nodeSequence","index","appendNodeAtIndex","getNodeAsync","createBlockFromData","blockData","blocksList","cover","stretched","isStretched","saveBlocks","html","innerHTML","childNodes","makeQueue","queue","getBlockData","makeFormDataFromBlocks","dataset","save","output","blockContent","pluginsContent","savedData","validate","result","classList","contains","push","currentNode","editorAreaHightlighted","sync","getNodeFocused","focused","selection","getSelection","anchorNode","focusNode","parentElement","isFirstLevelBlock","parent","markBlock","add","clearMark","remove","getFirstLevelBlock","node","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","position","text","blockChilds","textContent","trim","removeChild","lookingFromStart","getRange","getRangeAt","splitBlock","inputIndex","textBeforeCaret","textNodeBeforeCaret","textAfterCaret","textNodeAfterCaret","anchorNodeText","caretOffset","anchorOffset","currentBlock","substring","previousChilds","nextChilds","reachedCurrent","child","i","previousChildsLength","nextChildsLength","newNode","NEW_BLOCK_TYPE","mergeBlocks","targetInputIndex","targetInput","currentInputContent","paste","mutation","workingNode","allowedToPaste","sanitize","pasteTextContent","addedNodes","textNode","disconnect","cleaner","satinizer","Config","BASIC","clean","outerHTML","div","replaceWith","isLastNode","allChecked","allSiblingsEmpty_","sibling","wrapTextWithParagraphs","htmlString","paragraph","blockTyped","newWrapper","firstLevelBlocks","indexOf","tagName","cloneNode","defaultToolbarHeight","defaultOffset","opened","current","close","toggle","hidePlusButton","newYCoordinate","offsetTop","style","transform","Math","floor","hideRemoveActions","setting","toolType","makeSettings","settingsBlock","feedModeToggler","makeFeedModeToggler","isFeedModeActivated","updateFeedMode","removeBlockWrapper","settingButton","actionWrapper","confirmAction","cancelAction","removeButtonClicked","confirmRemovingRequest","cancelRemovingRequest","action","showRemoveActions","firstLevelBlocksCount","buttonsOpened","actionsOpened","wrappersOffset","storedSelection","showInlineToolbar","selectedText","getSelectionText","showButtons","getWrappersOffset","newCoordinateX","newCoordinateY","coords","getSelectionCoords","offsetHeight","x","left","y","scrollY","top","closeButtons","closeAction","createLinkAction","defaultToolAction","forEach","hightlight","offset","getOffset","_x","_y","isNaN","offsetLeft","clientLeft","clientTop","offsetParent","range","sel","createRange","collapse","boundingLeft","boundingTop","rangeCount","cloneRange","getClientRects","rect","toString","showActions","inlineToolbarAnchorInputKeydown_","keyCode","editable","restoreSelection","setAnchor","value","preventDefault","stopImmediatePropagation","clearRange","isActive","isLinkActive","saveSelection","inputForLink","focus","dataType","execCommand","containerEl","preSelectionRange","selectNodeContents","setEnd","startContainer","startOffset","end","savedSel","charIndex","setStart","nextCharIndex","nodeStack","foundStart","stop","pop","removeAllRanges","addRange","queryCommandState","setButtonHighlighted","removeButtonsHighLight","tag","leaf","currentTool","Object","barButtons","nextToolIndex","toolToSelect","visibleTool","appendCallback","UNREPLACEBLE_TOOLS","setToBlock","callbacks","enterKeyPressed","tabKeyPressed","enterKeyPressedOnRedactorZone","escapeKeyPressed","defaultKeyPressed","arrowKeyPressed","enterPressedOnBlock","contentEditable","saveCurrentInputIndex","isEnterPressedOnToolbar","enableLineBreaks","stopPropagation","shiftKey","currentSelection","currentSelectedNode","caretAtTheEndOfText","atTheEnd","isTextNodeHasParentBetweenContenteditable","islastNode","detectWhenClickedOnFirstLevelBlockArea","firstLevelBlock","indexOfLastInput","inputIsEmpty","currentNodeType","isInitialType","flag","blockRightOrDownArrowPressed","backspacePressed","blockLeftOrUpArrowPressed","focusedNodeHolder","focusedNode","editableElementIndex","lastChild","deepestTextnode","caretInLastChild","firstChild","caretInFirstChild","caretAtTheBeginning","setToPreviousBlock","selectionLength","endOffset","atStart","_blockPasteCallback","observer","MutationObserver","handleMutationsOnPaste","attributes","childList","characterData","subtree","observe","cleanData","fragment","clipboardData","getData","createDocumentFragment","lastNode","deleteContents","insertNode","setStartAfter","mutations","self","currentToolType","ceBlock","bar","placeholder","toggler","classname","toolIcon","toolTitle","properties","focusedNodeIndex","nodeToSet","childs","nextInput","emptyTextElement","lastChildNode","lengthOfLastChildNode","previousInput","pluginsRender","isFirstNode","isOffsetZero","errorThrown","errorMsg","message","notification","insertPastedContent","janitor","tags","a","href","rel","b","strong","em","span","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_RESULT__","root","factory","HTMLJanitor","tagDefinitions","validConfigValues","map","k","every","isBlockElement","blockElementNames","nodeName","isInlineElement","inlineElementNames","createTreeWalker","NodeFilter","SHOW_TEXT","SHOW_ELEMENT","SHOW_COMMENT","getAllowedAttrs","shouldRejectNode","allowedAttrs","shouldRejectAttr","attr","attrName","toLowerCase","sandbox","_sanitize","treeWalker","_sanitized","Node","TEXT_NODE","COMMENT_NODE","containsBlockElement","isInline","Array","some","isNotTopContainer","isNestedBlockElement","isInvalid","keepNestedBlockElements","removeAttribute","previousElementSibling","nextElementSibling"],"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.4.1\");\n\t\n\t var init = function init() {\n\t\n\t editor.core = __webpack_require__(1);\n\t editor.ui = __webpack_require__(2);\n\t editor.transport = __webpack_require__(3);\n\t editor.renderer = __webpack_require__(4);\n\t editor.saver = __webpack_require__(5);\n\t editor.content = __webpack_require__(6);\n\t editor.toolbar = __webpack_require__(7);\n\t editor.callback = __webpack_require__(11);\n\t editor.draw = __webpack_require__(12);\n\t editor.caret = __webpack_require__(13);\n\t editor.notifications = __webpack_require__(14);\n\t editor.parser = __webpack_require__(15);\n\t editor.sanitizer = __webpack_require__(16);\n\t };\n\t\n\t /**\n\t * @public\n\t *\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 textareaId: 'codex-editor',\n\t uploadImagesUrl: '/editor/transport/',\n\t\n\t // Type of block showing on empty editor\n\t initialBlockPlugin: 'paragraph'\n\t };\n\t\n\t /**\n\t * public\n\t *\n\t * Static nodes\n\t */\n\t editor.nodes = {\n\t textarea: null,\n\t wrapper: null,\n\t toolbar: null,\n\t inlineToolbar: {\n\t wrapper: null,\n\t buttons: null,\n\t actions: null\n\t },\n\t toolbox: null,\n\t notifications: null,\n\t plusButton: null,\n\t showSettingsButton: null,\n\t showTrashButton: null,\n\t blockSettings: null,\n\t pluginSettings: null,\n\t defaultSettings: null,\n\t toolbarButtons: {}, // { type : DomEl, ... }\n\t redactor: null\n\t };\n\t\n\t /**\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 {} userSettings are :\n\t * - tools [],\n\t * - textareaId String\n\t * ...\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.make).then(editor.ui.addTools).then(editor.ui.bindEvents).then(editor.ui.preparePlugins).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.2\n\t */\n\t\n\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (core) {\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.uploadImagesUrl) {\n\t\n\t editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;\n\t }\n\t\n\t editor.nodes.textarea = document.getElementById(userSettings.textareaId || editor.settings.textareaId);\n\t\n\t if (_typeof(editor.nodes.textarea) === undefined || editor.nodes.textarea === null) {\n\t\n\t reject(Error(\"Textarea wasn't found by ID: #\" + userSettings.textareaId));\n\t } else {\n\t\n\t resolve();\n\t }\n\t });\n\t };\n\t\n\t /**\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 };\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 * Native Ajax\n\t */\n\t core.ajax = function (data) {\n\t\n\t if (!data || !data.url) {\n\t\n\t return;\n\t }\n\t\n\t var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\n\t successFunction = function successFunction() {},\n\t params = '',\n\t obj;\n\t\n\t data.async = true;\n\t data.type = data.type || 'GET';\n\t data.data = data.data || '';\n\t data['content-type'] = data['content-type'] || 'application/json; charset=utf-8';\n\t successFunction = data.success || successFunction;\n\t\n\t if (data.type == 'GET' && data.data) {\n\t\n\t data.url = /\\?/.test(data.url) ? data.url + '&' + data.data : data.url + '?' + data.data;\n\t } else {\n\t\n\t for (obj in data.data) {\n\t\n\t params += obj + '=' + encodeURIComponent(data.data[obj]) + '&';\n\t }\n\t }\n\t\n\t if (data.withCredentials) {\n\t\n\t XMLHTTP.withCredentials = true;\n\t }\n\t\n\t if (data.beforeSend && typeof data.beforeSend == 'function') {\n\t\n\t data.beforeSend.call();\n\t }\n\t\n\t XMLHTTP.open(data.type, data.url, data.async);\n\t XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\t XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n\t\n\t XMLHTTP.onreadystatechange = function () {\n\t\n\t if (XMLHTTP.readyState == 4 && XMLHTTP.status == 200) {\n\t\n\t successFunction(XMLHTTP.responseText);\n\t }\n\t };\n\t\n\t XMLHTTP.send(params);\n\t };\n\t\n\t /**\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 instancePrefix = 'cdx-script-';\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(instancePrefix + 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 = instancePrefix + instanceName;\n\t\n\t script.onload = function () {\n\t\n\t resolve(scriptPath);\n\t };\n\t\n\t script.onerror = function () {\n\t\n\t reject(scriptPath);\n\t };\n\t\n\t script.src = scriptPath;\n\t document.head.appendChild(script);\n\t });\n\t };\n\t\n\t return core;\n\t}({});\n\n/***/ },\n/* 2 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor UI module\n\t *\n\t * @author Codex Team\n\t * @version 1.1\n\t */\n\t\n\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (ui) {\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} - highlights covered blocks\n\t */\n\t BLOCK_IN_FEED_MODE: 'ce-block--feed-mode',\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.make = function () {\n\t\n\t var wrapper, toolbar, toolbarContent, redactor, notifications, blockButtons, blockSettings, showSettingsButton, showTrashButton, toolbox, plusButton;\n\t\n\t /** Make editor wrapper */\n\t wrapper = editor.draw.wrapper();\n\t\n\t /** Append editor wrapper after initial textarea */\n\t editor.core.insertAfter(editor.nodes.textarea, wrapper);\n\t\n\t /** Append block with notifications to the document */\n\t notifications = editor.draw.alertsHolder();\n\t editor.nodes.notifications = document.body.appendChild(notifications);\n\t\n\t /** Make toolbar and content-editable redactor */\n\t toolbar = editor.draw.toolbar();\n\t toolbarContent = editor.draw.toolbarContent();\n\t plusButton = editor.draw.plusButton();\n\t showSettingsButton = editor.draw.settingsButton();\n\t showTrashButton = editor.toolbar.settings.makeRemoveBlockButton();\n\t blockSettings = editor.draw.blockSettings();\n\t blockButtons = editor.draw.blockButtons();\n\t toolbox = editor.draw.toolbox();\n\t redactor = editor.draw.redactor();\n\t\n\t /** settings */\n\t var defaultSettings = editor.draw.defaultSettings(),\n\t pluginSettings = editor.draw.pluginsSettings();\n\t\n\t /** Add default and plugins settings */\n\t blockSettings.appendChild(pluginSettings);\n\t blockSettings.appendChild(defaultSettings);\n\t\n\t /** Make blocks buttons\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 /** Append plus button */\n\t toolbarContent.appendChild(plusButton);\n\t\n\t /** Appending toolbar tools */\n\t toolbarContent.appendChild(toolbox);\n\t\n\t /** Appending first-level block buttons */\n\t toolbar.appendChild(blockButtons);\n\t\n\t /** Append toolbarContent to toolbar */\n\t toolbar.appendChild(toolbarContent);\n\t\n\t wrapper.appendChild(toolbar);\n\t\n\t wrapper.appendChild(redactor);\n\t\n\t /** Save created ui-elements to static nodes state */\n\t editor.nodes.wrapper = wrapper;\n\t editor.nodes.toolbar = toolbar;\n\t editor.nodes.plusButton = plusButton;\n\t editor.nodes.toolbox = toolbox;\n\t editor.nodes.blockSettings = blockSettings;\n\t editor.nodes.pluginSettings = pluginSettings;\n\t editor.nodes.defaultSettings = defaultSettings;\n\t editor.nodes.showSettingsButton = showSettingsButton;\n\t editor.nodes.showTrashButton = showTrashButton;\n\t\n\t editor.nodes.redactor = redactor;\n\t\n\t /** Make container for inline toolbar */\n\t editor.ui.makeInlineToolbar();\n\t\n\t /** fill in default settings */\n\t editor.toolbar.settings.addDefaultSettings();\n\t };\n\t\n\t ui.makeInlineToolbar = function () {\n\t\n\t var container = editor.draw.inlineToolbar();\n\t\n\t /** Append to redactor new inline block */\n\t editor.nodes.inlineToolbar.wrapper = container;\n\t\n\t /** Draw toolbar buttons */\n\t editor.nodes.inlineToolbar.buttons = editor.draw.inlineToolbarButtons();\n\t\n\t /** Buttons action or settings */\n\t editor.nodes.inlineToolbar.actions = editor.draw.inlineToolbarActions();\n\t\n\t /** Append to inline toolbar buttons as part of it */\n\t editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.buttons);\n\t editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.actions);\n\t\n\t editor.nodes.wrapper.appendChild(editor.nodes.inlineToolbar.wrapper);\n\t };\n\t\n\t /**\n\t * @private\n\t * Append tools passed in editor.tools\n\t */\n\t ui.addTools = function () {\n\t\n\t var tool, toolName, toolButton;\n\t\n\t for (toolName in editor.settings.tools) {\n\t\n\t tool = editor.settings.tools[toolName];\n\t\n\t editor.tools[toolName] = tool;\n\t\n\t if (!tool.iconClassname) {\n\t\n\t editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\n\t continue;\n\t }\n\t\n\t if (typeof tool.render != 'function') {\n\t\n\t editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\n\t continue;\n\t }\n\t\n\t if (!tool.displayInToolbox) {\n\t\n\t continue;\n\t } else {\n\t\n\t /** if tools is for toolbox */\n\t toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\n\t\n\t editor.nodes.toolbox.appendChild(toolButton);\n\t\n\t editor.nodes.toolbarButtons[toolName] = toolButton;\n\t }\n\t }\n\t\n\t /**\n\t * Add inline toolbar tools\n\t */\n\t editor.ui.addInlineToolbarTools();\n\t };\n\t\n\t ui.addInlineToolbarTools = function () {\n\t\n\t var tools = {\n\t\n\t bold: {\n\t icon: 'ce-icon-bold',\n\t command: 'bold'\n\t },\n\t\n\t italic: {\n\t icon: 'ce-icon-italic',\n\t command: 'italic'\n\t },\n\t\n\t underline: {\n\t icon: 'ce-icon-underline',\n\t command: 'underline'\n\t },\n\t\n\t link: {\n\t icon: 'ce-icon-link',\n\t command: 'createLink'\n\t }\n\t };\n\t\n\t var toolButton, tool;\n\t\n\t for (var name in tools) {\n\t\n\t tool = tools[name];\n\t\n\t toolButton = editor.draw.toolbarButtonInline(name, tool.icon);\n\t\n\t editor.nodes.inlineToolbar.buttons.appendChild(toolButton);\n\t /**\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 ui.bindEvents = function () {\n\t\n\t editor.core.log('ui.bindEvents fired', 'info');\n\t\n\t // window.addEventListener('error', function (errorMsg, url, lineNumber) {\n\t // editor.notifications.errorThrown(errorMsg, event);\n\t // }, false );\n\t\n\t /** All keydowns on Document */\n\t document.addEventListener('keydown', editor.callback.globalKeydown, false);\n\t\n\t /** All keydowns on Redactor zone */\n\t editor.nodes.redactor.addEventListener('keydown', editor.callback.redactorKeyDown, false);\n\t\n\t /** All keydowns on Document */\n\t document.addEventListener('keyup', editor.callback.globalKeyup, false);\n\t\n\t /**\n\t * Mouse click to radactor\n\t */\n\t editor.nodes.redactor.addEventListener('click', editor.callback.redactorClicked, false);\n\t\n\t /**\n\t * Clicks to the Plus button\n\t */\n\t editor.nodes.plusButton.addEventListener('click', editor.callback.plusButtonClicked, false);\n\t\n\t /**\n\t * Clicks to SETTINGS button in toolbar\n\t */\n\t editor.nodes.showSettingsButton.addEventListener('click', editor.callback.showSettingsButtonClicked, false);\n\t\n\t /**\n\t * @deprecated ( but now in use for syncronization );\n\t * Any redactor changes: keyboard input, mouse cut/paste, drag-n-drop text\n\t */\n\t // editor.nodes.redactor.addEventListener('input', editor.callback.redactorInputEvent, false );\n\t\n\t /** Bind click listeners on toolbar buttons */\n\t for (var button in editor.nodes.toolbarButtons) {\n\t\n\t editor.nodes.toolbarButtons[button].addEventListener('click', editor.callback.toolbarButtonClicked, false);\n\t }\n\t };\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 ui.preparePlugins = function () {\n\t\n\t return new Promise(function (resolve, reject) {\n\t\n\t var pluginName = void 0,\n\t plugin = void 0;\n\t\n\t for (pluginName in editor.tools) {\n\t\n\t plugin = editor.tools[pluginName];\n\t\n\t if (typeof plugin.prepare != 'function') {\n\t\n\t continue;\n\t }\n\t\n\t plugin.prepare(plugin.config || {}).then(function () {\n\t\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 ui.addBlockHandlers = function (block) {\n\t\n\t if (!block) return;\n\t\n\t /**\n\t * Block keydowns\n\t */\n\t block.addEventListener('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 block.addEventListener('paste', editor.callback.blockPasteCallback, false);\n\t\n\t block.addEventListener('mouseup', editor.toolbar.inline.show, false);\n\t };\n\t\n\t /** getting all contenteditable elements */\n\t ui.saveInputs = function () {\n\t\n\t var redactor = editor.nodes.redactor;\n\t\n\t /** Save all inputs in global variable state */\n\t editor.state.inputs = redactor.querySelectorAll('[contenteditable], input');\n\t };\n\t\n\t /**\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', 'Расскажите свою историю...');\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 button.addEventListener('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/* 3 */\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 * @author Codex Team\n\t * @version 1.0\n\t */\n\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (transport) {\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 transport.prepare = function () {\n\t\n\t var input = document.createElement('INPUT');\n\t\n\t input.type = 'file';\n\t input.addEventListener('change', editor.transport.fileSelected);\n\t\n\t editor.transport.input = input;\n\t };\n\t\n\t /** Clear input when files is uploaded */\n\t transport.clearInput = function () {\n\t\n\t /** Remove old input */\n\t this.input = null;\n\t\n\t /** Prepare new one */\n\t this.prepare();\n\t };\n\t\n\t /**\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 files = input.files,\n\t formdData = new FormData();\n\t\n\t formdData.append('files', files[0], files[0].name);\n\t\n\t editor.transport.ajax({\n\t data: formdData,\n\t beforeSend: editor.transport.arguments.beforeSend,\n\t success: editor.transport.arguments.success,\n\t error: editor.transport.arguments.error\n\t });\n\t };\n\t\n\t /**\n\t * Use plugin callbacks\n\t * @protected\n\t */\n\t transport.selectAndUpload = function (args) {\n\t\n\t this.arguments = args;\n\t this.input.click();\n\t };\n\t\n\t /**\n\t * Ajax requests module\n\t * @todo use core.ajax\n\t */\n\t transport.ajax = function (params) {\n\t\n\t var xhr = new XMLHttpRequest(),\n\t beforeSend = typeof params.beforeSend == 'function' ? params.beforeSend : function () {},\n\t success = typeof params.success == 'function' ? params.success : function () {},\n\t error = typeof params.error == 'function' ? params.error : function () {};\n\t\n\t beforeSend();\n\t\n\t xhr.open('POST', editor.settings.uploadImagesUrl, true);\n\t\n\t xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\t\n\t xhr.onload = function () {\n\t\n\t if (xhr.status === 200) {\n\t\n\t success(xhr.responseText);\n\t } else {\n\t\n\t editor.core.log('request error: %o', xhr);\n\t error();\n\t }\n\t };\n\t\n\t xhr.send(params.data);\n\t this.clearInput();\n\t };\n\t\n\t return transport;\n\t}({});\n\n/***/ },\n/* 4 */\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\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (renderer) {\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.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 blocksList[index];\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} blockData looks like\n\t * { header : {\n\t * text: '',\n\t * type: 'H3', ...\n\t * }\n\t * }\n\t * @return {object} with type and Element\n\t */\n\t renderer.createBlockFromData = function (blockData) {\n\t\n\t /** New parser */\n\t var pluginName = blockData.type,\n\t cover = blockData.cover;\n\t\n\t /** Get first key of object that stores plugin name */\n\t // for (var pluginName in blockData) break;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].render != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have \\xABrender\\xBB method');\n\t }\n\t\n\t /** New Parser */\n\t var block = editor.tools[pluginName].render(blockData.data);\n\t\n\t /** is first-level block stretched */\n\t var stretched = editor.tools[pluginName].isStretched || false;\n\t\n\t /** Retrun type and block */\n\t return {\n\t type: pluginName,\n\t block: block,\n\t stretched: stretched,\n\t cover: cover\n\t };\n\t };\n\t\n\t return renderer;\n\t}({});\n\n/***/ },\n/* 5 */\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.0.2\n\t */\n\t\n\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (saver) {\n\t\n\t /**\n\t * Saves blocks\n\t * @private\n\t */\n\t saver.saveBlocks = function () {\n\t\n\t /** Save html content of redactor to memory */\n\t editor.state.html = editor.nodes.redactor.innerHTML;\n\t\n\t /** Empty jsonOutput state */\n\t editor.state.jsonOutput = [];\n\t\n\t Promise.resolve().then(function () {\n\t\n\t return editor.nodes.redactor.childNodes;\n\t })\n\t /** Making a sequence from separate blocks */\n\t .then(editor.saver.makeQueue).then(function () {\n\t // editor.nodes.textarea.innerHTML = editor.state.html;\n\t }).catch(function (error) {\n\t\n\t editor.core.log(error);\n\t });\n\t };\n\t\n\t saver.makeQueue = function (blocks) {\n\t\n\t var queue = Promise.resolve();\n\t\n\t for (var index = 0; index < blocks.length; index++) {\n\t\n\t /** Add node to sequence at specified index */\n\t editor.saver.getBlockData(queue, blocks, index);\n\t }\n\t };\n\t\n\t /** Gets every block and makes From Data */\n\t saver.getBlockData = function (queue, blocks, index) {\n\t\n\t queue.then(function () {\n\t\n\t return editor.saver.getNodeAsync(blocks, index);\n\t }).then(editor.saver.makeFormDataFromBlocks);\n\t };\n\t\n\t /**\n\t * Asynchronously returns block data from blocksList by index\n\t * @return Promise to node\n\t */\n\t saver.getNodeAsync = function (blocksList, index) {\n\t\n\t return Promise.resolve().then(function () {\n\t\n\t return blocksList[index];\n\t });\n\t };\n\t\n\t saver.makeFormDataFromBlocks = function (block) {\n\t\n\t var pluginName = block.dataset.tool;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].save != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have save method');\n\t }\n\t\n\t /** Result saver */\n\t var blockContent = block.childNodes[0],\n\t pluginsContent = blockContent.childNodes[0],\n\t savedData = editor.tools[pluginName].save(pluginsContent),\n\t output;\n\t\n\t output = {\n\t type: pluginName,\n\t data: savedData\n\t };\n\t\n\t if (editor.tools[pluginName].validate) {\n\t\n\t var result = editor.tools[pluginName].validate(savedData);\n\t\n\t /**\n\t * Do not allow invalid data\n\t */\n\t if (!result) return;\n\t }\n\t\n\t /** Marks Blocks that will be in main page */\n\t output.cover = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t\n\t editor.state.jsonOutput.push(output);\n\t };\n\t\n\t return saver;\n\t}({});\n\n/***/ },\n/* 6 */\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 * @author Codex Team\n\t * @version 1.3.11\n\t */\n\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (content) {\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 * 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 * @deprecated\n\t */\n\t content.getNodeFocused = function () {\n\t\n\t var selection = window.getSelection(),\n\t focused;\n\t\n\t if (selection.anchorNode === null) {\n\t\n\t return null;\n\t }\n\t\n\t if (selection.anchorNode.nodeType == editor.core.nodeTypes.TAG) {\n\t\n\t focused = selection.anchorNode;\n\t } else {\n\t\n\t focused = selection.focusNode.parentElement;\n\t }\n\t\n\t if (!editor.parser.isFirstLevelBlock(focused)) {\n\t\n\t /** Iterate with parent nodes to find first-level*/\n\t var parent = focused.parentNode;\n\t\n\t while (parent && !editor.parser.isFirstLevelBlock(parent)) {\n\t\n\t parent = parent.parentNode;\n\t }\n\t\n\t focused = parent;\n\t }\n\t\n\t if (focused != editor.nodes.redactor) {\n\t\n\t return focused;\n\t }\n\t\n\t return null;\n\t };\n\t\n\t /**\n\t * Appends background to the block\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 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 * @private\n\t *\n\t * Finds first-level block\n\t * @param {Element} node - selected or clicked in redactors area node\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 * 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 this.currentNode = this.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 /**\n\t * Check is this block was in feed\n\t * If true, than set switched block also covered\n\t */\n\t if (targetBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE)) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t }\n\t\n\t /** 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 * @private\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 cover = blockData.cover,\n\t isStretched = blockData.stretched;\n\t\n\t var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched);\n\t\n\t if (cover === true) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t }\n\t\n\t if (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 var newBlockComposed = editor.content.composeNewBlock(newBlock, tool);\n\t\n\t /** Replacing */\n\t editor.content.replaceBlock(blockToReplace, newBlockComposed);\n\t\n\t /** Save new Inputs when block is changed */\n\t editor.ui.saveInputs();\n\t };\n\t\n\t /**\n\t * Iterates between child noted and looking for #text node on deepest level\n\t * @private\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 */\n\t content.composeNewBlock = function (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 */\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 * @private\n\t * @param {Int} inputIndex - target input index\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 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 * @private\n\t *\n\t * Callback for HTML Mutations\n\t * @param {Array} mutation - Mutation Record\n\t */\n\t content.paste = function (mutation) {\n\t\n\t var workingNode = editor.content.currentNode,\n\t tool = workingNode.dataset.tool;\n\t\n\t if (editor.tools[tool].allowedToPaste) {\n\t\n\t editor.content.sanitize.call(this, mutation.target);\n\t } else {\n\t\n\t editor.content.pasteTextContent(mutation.addedNodes);\n\t }\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * gets only text/plain content of node\n\t * @param {Element} target - HTML node\n\t */\n\t content.pasteTextContent = function (nodes) {\n\t\n\t var node = nodes[0],\n\t textNode;\n\t\n\t if (!node) {\n\t\n\t return;\n\t }\n\t\n\t if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\t\n\t textNode = document.createTextNode(node);\n\t } else {\n\t\n\t textNode = document.createTextNode(node.textContent);\n\t }\n\t\n\t if (editor.core.isDomNode(node)) {\n\t\n\t node.parentNode.replaceChild(textNode, node);\n\t }\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Sanitizes HTML content\n\t * @param {Element} target - inserted element\n\t * @uses Sanitize library html-janitor\n\t */\n\t content.sanitize = function (target) {\n\t\n\t if (!target) {\n\t\n\t return;\n\t }\n\t\n\t var node = target[0];\n\t\n\t if (!node) {\n\t\n\t return;\n\t }\n\t\n\t /**\n\t * Disconnect Observer\n\t * hierarchy of function calls inherits context of observer\n\t */\n\t this.disconnect();\n\t\n\t /**\n\t * Don't sanitize text node\n\t */\n\t if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\t\n\t return;\n\t }\n\t\n\t /**\n\t * Clear dirty content\n\t */\n\t var cleaner = editor.sanitizer.init(editor.satinizer.Config.BASIC),\n\t clean = cleaner.clean(target.outerHTML);\n\t\n\t var div = editor.draw.node('DIV', [], { innerHTML: clean });\n\t\n\t node.replaceWith(div.childNodes[0]);\n\t };\n\t\n\t /**\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] htmlString - html content as string\n\t * @return {string} - html content as string\n\t */\n\t content.wrapTextWithParagraphs = function (htmlString) {\n\t\n\t var wrapper = document.createElement('DIV'),\n\t newWrapper = document.createElement('DIV'),\n\t i,\n\t paragraph,\n\t firstLevelBlocks = ['DIV', 'P'],\n\t blockTyped,\n\t node;\n\t\n\t /**\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 = htmlString;\n\t paragraph = document.createElement('P');\n\t\n\t for (i = 0; i < wrapper.childNodes.length; i++) {\n\t\n\t node = wrapper.childNodes[i];\n\t\n\t blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1;\n\t\n\t /**\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 return content;\n\t}({});\n\n/***/ },\n/* 7 */\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\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (toolbar) {\n\t\n\t toolbar.settings = __webpack_require__(8);\n\t toolbar.inline = __webpack_require__(9);\n\t toolbar.toolbox = __webpack_require__(10);\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 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/* 8 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Toolbar settings\n\t *\n\t * @version 1.0.4\n\t */\n\t\n\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (settings) {\n\t\n\t settings.opened = false;\n\t\n\t settings.setting = null;\n\t settings.actions = null;\n\t\n\t settings.cover = null;\n\t\n\t /**\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 editor.core.log('Plugin \\xAB' + toolType + '\\xBB has no settings', 'warn');\n\t // editor.nodes.pluginSettings.innerHTML = `Плагин «${toolType}» не имеет настроек`;\n\t } else {\n\t\n\t /**\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\n\t /** Open settings block */\n\t editor.nodes.blockSettings.classList.add('opened');\n\t editor.toolbar.settings.addDefaultSettings();\n\t this.opened = true;\n\t };\n\t\n\t /**\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 * This function adds default core settings\n\t */\n\t settings.addDefaultSettings = function () {\n\t\n\t /** list of default settings */\n\t var feedModeToggler;\n\t\n\t /** Clear block and append initialized settings */\n\t editor.nodes.defaultSettings.innerHTML = '';\n\t\n\t /** Init all default setting buttons */\n\t feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();\n\t\n\t /**\n\t * Fill defaultSettings\n\t */\n\t\n\t /**\n\t * Button that enables/disables Feed-mode\n\t * Feed-mode means that block will be showed in articles-feed like cover\n\t */\n\t editor.nodes.defaultSettings.appendChild(feedModeToggler);\n\t };\n\t\n\t /**\n\t * Cover setting.\n\t * This tune highlights block, so that it may be used for showing target block on main page\n\t * Draw different setting when block is marked for main page\n\t * If TRUE, then we show button that removes this selection\n\t * Also defined setting \"Click\" events will be listened and have separate callbacks\n\t *\n\t * @return {Element} node/button that we place in default settings block\n\t */\n\t settings.makeFeedModeToggler = function () {\n\t\n\t var isFeedModeActivated = editor.toolbar.settings.isFeedModeActivated(),\n\t setting,\n\t data;\n\t\n\t if (!isFeedModeActivated) {\n\t\n\t data = {\n\t innerHTML: '<i class=\"ce-icon-newspaper\"></i>Вывести в ленте'\n\t };\n\t } else {\n\t\n\t data = {\n\t innerHTML: '<i class=\"ce-icon-newspaper\"></i>Не выводить в ленте'\n\t };\n\t }\n\t\n\t setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\n\t setting.addEventListener('click', editor.toolbar.settings.updateFeedMode, false);\n\t\n\t return setting;\n\t };\n\t\n\t /**\n\t * Updates Feed-mode\n\t */\n\t settings.updateFeedMode = function () {\n\t\n\t var currentNode = editor.content.currentNode;\n\t\n\t currentNode.classList.toggle(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t settings.isFeedModeActivated = function () {\n\t\n\t var currentBlock = editor.content.currentNode;\n\t\n\t if (currentBlock) {\n\t\n\t return currentBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t } else {\n\t\n\t return false;\n\t }\n\t };\n\t\n\t /**\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 settingButton.addEventListener('click', editor.toolbar.settings.removeButtonClicked, false);\n\t\n\t confirmAction.addEventListener('click', editor.toolbar.settings.confirmRemovingRequest, false);\n\t\n\t cancelAction.addEventListener('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/* 9 */\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\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (inline) {\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 (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 action.addEventListener('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/* 10 */\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\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (toolbox) {\n\t\n\t toolbox.opened = false;\n\t\n\t /** Shows toolbox */\n\t toolbox.open = function () {\n\t\n\t /** Close setting if toolbox is opened */\n\t if (editor.toolbar.settings.opened) {\n\t\n\t editor.toolbar.settings.close();\n\t }\n\t\n\t /** display toolbox */\n\t editor.nodes.toolbox.classList.add('opened');\n\t\n\t /** Animate plus button */\n\t editor.nodes.plusButton.classList.add('clicked');\n\t\n\t /** toolbox state */\n\t editor.toolbar.toolbox.opened = true;\n\t };\n\t\n\t /** Closes toolbox */\n\t toolbox.close = function () {\n\t\n\t /** Makes toolbox disapear */\n\t editor.nodes.toolbox.classList.remove('opened');\n\t\n\t /** Rotate plus button */\n\t editor.nodes.plusButton.classList.remove('clicked');\n\t\n\t /** toolbox state */\n\t editor.toolbar.toolbox.opened = false;\n\t };\n\t\n\t toolbox.leaf = function () {\n\t\n\t var currentTool = editor.toolbar.current,\n\t tools = Object.keys(editor.tools),\n\t barButtons = editor.nodes.toolbarButtons,\n\t nextToolIndex = 0,\n\t toolToSelect = void 0,\n\t visibleTool = void 0,\n\t tool = void 0;\n\t\n\t if (!currentTool) {\n\t\n\t /** Get first tool from object*/\n\t for (tool in editor.tools) {\n\t\n\t if (editor.tools[tool].displayInToolbox) {\n\t\n\t break;\n\t }\n\t\n\t nextToolIndex++;\n\t }\n\t } else {\n\t\n\t nextToolIndex = tools.indexOf(currentTool) + 1;\n\t visibleTool = tools[nextToolIndex];\n\t\n\t while (!editor.tools[visibleTool].displayInToolbox) {\n\t\n\t nextToolIndex++;\n\t visibleTool = tools[nextToolIndex];\n\t\n\t if (nextToolIndex == tools.length) {\n\t\n\t nextToolIndex = 0;\n\t visibleTool = tools[nextToolIndex];\n\t }\n\t }\n\t }\n\t\n\t toolToSelect = tools[nextToolIndex];\n\t\n\t for (var button in barButtons) {\n\t\n\t barButtons[button].classList.remove('selected');\n\t }\n\t\n\t barButtons[toolToSelect].classList.add('selected');\n\t editor.toolbar.current = toolToSelect;\n\t };\n\t\n\t /**\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/* 11 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor callbacks module\n\t *\n\t * @author Codex Team\n\t * @version 1.3.7\n\t */\n\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (callbacks) {\n\t\n\t callbacks.globalKeydown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.redactorKeyDown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.TAB:\n\t editor.callback.tabKeyPressed(event);break;\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressedOnRedactorZone(event);break;\n\t case editor.core.keys.ESC:\n\t editor.callback.escapeKeyPressed(event);break;\n\t default:\n\t editor.callback.defaultKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.globalKeyup = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.UP:\n\t case editor.core.keys.LEFT:\n\t case editor.core.keys.RIGHT:\n\t case editor.core.keys.DOWN:\n\t editor.callback.arrowKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.tabKeyPressed = function (event) {\n\t\n\t if (!editor.toolbar.opened) {\n\t\n\t editor.toolbar.open();\n\t }\n\t\n\t if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\t\n\t editor.toolbar.toolbox.open();\n\t } else {\n\t\n\t editor.toolbar.toolbox.leaf();\n\t }\n\t\n\t event.preventDefault();\n\t };\n\t\n\t /**\n\t * @param {Event} event\n\t */\n\t callbacks.enterKeyPressed = function () {\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 editor.callback.enterPressedOnBlock();\n\t }\n\t };\n\t\n\t /**\n\t * ENTER key handler\n\t * Makes new paragraph block\n\t */\n\t callbacks.enterKeyPressedOnRedactorZone = function (event) {\n\t\n\t if (event.target.contentEditable == 'true') {\n\t\n\t /** Update input index */\n\t editor.caret.saveCurrentInputIndex();\n\t }\n\t\n\t var currentInputIndex = editor.caret.getCurrentInputIndex() || 0,\n\t workingNode = editor.content.currentNode,\n\t tool = workingNode.dataset.tool,\n\t isEnterPressedOnToolbar = editor.toolbar.opened && editor.toolbar.current && event.target == editor.state.inputs[currentInputIndex];\n\t\n\t /** The list of tools which needs the default browser behaviour */\n\t var enableLineBreaks = editor.tools[tool].enableLineBreaks;\n\t\n\t /** This type of block creates when enter is pressed */\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\t\n\t /**\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 callbacks.escapeKeyPressed = function (event) {\n\t\n\t /** Close all toolbar */\n\t editor.toolbar.close();\n\t\n\t /** Close toolbox */\n\t editor.toolbar.toolbox.close();\n\t\n\t event.preventDefault();\n\t };\n\t\n\t /**\n\t * @param {Event} event\n\t */\n\t callbacks.arrowKeyPressed = function () {\n\t\n\t editor.content.workingNodeChanged();\n\t\n\t /* Closing toolbar */\n\t editor.toolbar.close();\n\t editor.toolbar.move();\n\t };\n\t\n\t /**\n\t * @param {Event} event\n\t */\n\t callbacks.defaultKeyPressed = function () {\n\t\n\t editor.toolbar.close();\n\t\n\t if (!editor.toolbar.inline.actionsOpened) {\n\t\n\t editor.toolbar.inline.close();\n\t editor.content.clearMark();\n\t }\n\t };\n\t\n\t callbacks.redactorClicked = function (event) {\n\t\n\t callbacks.detectWhenClickedOnFirstLevelBlockArea();\n\t\n\t editor.content.workingNodeChanged(event.target);\n\t\n\t editor.ui.saveInputs();\n\t\n\t var selectedText = editor.toolbar.inline.getSelectionText(),\n\t firstLevelBlock;\n\t\n\t /**\n\t * If selection range took off, then we hide inline toolbar\n\t */\n\t if (selectedText.length === 0) {\n\t\n\t editor.toolbar.inline.close();\n\t }\n\t\n\t /** Update current input index in memory when caret focused into existed input */\n\t if (event.target.contentEditable == 'true') {\n\t\n\t editor.caret.saveCurrentInputIndex();\n\t }\n\t\n\t if (editor.content.currentNode === null) {\n\t\n\t /**\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 /**\n\t * @todo Refactor\n\t */\n\t\n\t /** getting firstlevel parent of input */\n\t firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);\n\t }\n\t\n\t /** If input is empty, then we set caret to the last input */\n\t if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {\n\t\n\t editor.caret.setToBlock(indexOfLastInput);\n\t } else {\n\t\n\t /** Create new input when caret clicked in redactors area */\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\t\n\t editor.content.insertBlock({\n\t type: NEW_BLOCK_TYPE,\n\t block: editor.tools[NEW_BLOCK_TYPE].render()\n\t });\n\t\n\t /** If there is no inputs except inserted */\n\t if (editor.state.inputs.length === 1) {\n\t\n\t editor.caret.setToBlock(indexOfLastInput);\n\t } else {\n\t\n\t /** Set caret to this appended input */\n\t editor.caret.setToNextBlock(indexOfLastInput);\n\t }\n\t }\n\t\n\t /**\n\t * Move toolbar to the right position and open\n\t */\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t } else {\n\t\n\t /**\n\t * Move toolbar to the new position and open\n\t */\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t\n\t /** Close all panels */\n\t editor.toolbar.settings.close();\n\t editor.toolbar.toolbox.close();\n\t }\n\t\n\t var inputIsEmpty = !editor.content.currentNode.textContent.trim(),\n\t currentNodeType = editor.content.currentNode.dataset.tool,\n\t isInitialType = currentNodeType == editor.settings.initialBlockPlugin;\n\t\n\t /** Hide plus buttons */\n\t editor.toolbar.hidePlusButton();\n\t\n\t /** Mark current block */\n\t editor.content.markBlock();\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 * 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 callbacks.detectWhenClickedOnFirstLevelBlockArea = function () {\n\t\n\t var selection = window.getSelection(),\n\t anchorNode = selection.anchorNode,\n\t flag = false;\n\t\n\t if (selection.rangeCount === 0) {\n\t\n\t editor.content.editorAreaHightlighted = true;\n\t } else {\n\t\n\t if (!editor.core.isDomNode(anchorNode)) {\n\t\n\t anchorNode = anchorNode.parentNode;\n\t }\n\t\n\t /** Already founded, without loop */\n\t if (anchorNode.contentEditable == 'true') {\n\t\n\t flag = true;\n\t }\n\t\n\t while (anchorNode.contentEditable != 'true') {\n\t\n\t anchorNode = anchorNode.parentNode;\n\t\n\t if (anchorNode.contentEditable == 'true') {\n\t\n\t flag = true;\n\t }\n\t\n\t if (anchorNode == document.body) {\n\t\n\t break;\n\t }\n\t }\n\t\n\t /** If editable element founded, flag is \"TRUE\", Therefore we return \"FALSE\" */\n\t editor.content.editorAreaHightlighted = flag ? false : true;\n\t }\n\t };\n\t\n\t /**\n\t * Toolbar button click handler\n\t * @param this - cursor to the button\n\t */\n\t callbacks.toolbarButtonClicked = function (event) {\n\t\n\t var button = this;\n\t\n\t editor.toolbar.current = button.dataset.type;\n\t\n\t editor.toolbar.toolbox.toolClicked(event);\n\t editor.toolbar.close();\n\t };\n\t\n\t /** Show or Hide toolbox when plus button is clicked */\n\t callbacks.plusButtonClicked = function () {\n\t\n\t if (!editor.nodes.toolbox.classList.contains('opened')) {\n\t\n\t editor.toolbar.toolbox.open();\n\t } else {\n\t\n\t editor.toolbar.toolbox.close();\n\t }\n\t };\n\t\n\t /**\n\t * Block handlers for KeyDown events\n\t */\n\t callbacks.blockKeydown = function (event) {\n\t\n\t var block = this; // event.target input\n\t\n\t switch (event.keyCode) {\n\t\n\t case editor.core.keys.DOWN:\n\t case editor.core.keys.RIGHT:\n\t editor.callback.blockRightOrDownArrowPressed();\n\t break;\n\t\n\t case editor.core.keys.BACKSPACE:\n\t editor.callback.backspacePressed(block, event);\n\t break;\n\t\n\t case editor.core.keys.UP:\n\t case editor.core.keys.LEFT:\n\t editor.callback.blockLeftOrUpArrowPressed();\n\t break;\n\t\n\t }\n\t };\n\t\n\t /**\n\t * RIGHT or DOWN keydowns on block\n\t */\n\t callbacks.blockRightOrDownArrowPressed = function () {\n\t\n\t var selection = window.getSelection(),\n\t inputs = editor.state.inputs,\n\t focusedNode = selection.anchorNode,\n\t focusedNodeHolder;\n\t\n\t /** Check for caret existance */\n\t if (!focusedNode) {\n\t\n\t return false;\n\t }\n\t\n\t /** Looking for closest (parent) contentEditable element of focused node */\n\t while (focusedNode.contentEditable != 'true') {\n\t\n\t focusedNodeHolder = focusedNode.parentNode;\n\t focusedNode = focusedNodeHolder;\n\t }\n\t\n\t /** Input index in DOM level */\n\t var editableElementIndex = 0;\n\t\n\t while (focusedNode != inputs[editableElementIndex]) {\n\t\n\t editableElementIndex++;\n\t }\n\t\n\t /**\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 callbacks.blockLeftOrUpArrowPressed = function () {\n\t\n\t var selection = window.getSelection(),\n\t inputs = editor.state.inputs,\n\t focusedNode = selection.anchorNode,\n\t focusedNodeHolder;\n\t\n\t /** Check for caret existance */\n\t if (!focusedNode) {\n\t\n\t return false;\n\t }\n\t\n\t /**\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 * Callback for enter key pressing in first-level block area\n\t * @param {Event} event\n\t */\n\t callbacks.enterPressedOnBlock = function () {\n\t\n\t var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\t\n\t editor.content.insertBlock({\n\t type: NEW_BLOCK_TYPE,\n\t block: editor.tools[NEW_BLOCK_TYPE].render()\n\t }, true);\n\t\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t };\n\t\n\t callbacks.backspacePressed = function (block, event) {\n\t\n\t var currentInputIndex = editor.caret.getCurrentInputIndex(),\n\t range,\n\t selectionLength,\n\t firstLevelBlocksCount;\n\t\n\t if (block.textContent.trim()) {\n\t\n\t range = editor.content.getRange();\n\t selectionLength = range.endOffset - range.startOffset;\n\t\n\t if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {\n\t\n\t editor.content.mergeBlocks(currentInputIndex);\n\t } else {\n\t\n\t return;\n\t }\n\t }\n\t\n\t if (!selectionLength) {\n\t\n\t block.remove();\n\t }\n\t\n\t firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\t\n\t /**\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 * This method is used to observe pasted dirty data.\n\t *\n\t * Mutation handlers send to separate observers each mutation (added, changed and so on), which will be\n\t * passed from handler that sanitizes and replaces data.\n\t *\n\t * Probably won't be used\n\t *\n\t * @deprecated\n\t *\n\t * @param event\n\t * @private\n\t */\n\t callbacks._blockPasteCallback = function () {\n\t\n\t var currentInputIndex = editor.caret.getCurrentInputIndex();\n\t\n\t /**\n\t * create an observer instance\n\t */\n\t var observer = new MutationObserver(editor.callback.handleMutationsOnPaste);\n\t\n\t /**\n\t * configuration of the observer:\n\t */\n\t var config = {\n\t attributes: true,\n\t childList: false,\n\t characterData: false,\n\t subtree: true\n\t };\n\t\n\t // pass in the target node, as well as the observer options\n\t observer.observe(editor.state.inputs[currentInputIndex], config);\n\t };\n\t\n\t /**\n\t * This method prevents default behaviour.\n\t *\n\t * 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 * @param event\n\t */\n\t callbacks.blockPasteCallback = function (event) {\n\t\n\t /** Prevent default behaviour */\n\t event.preventDefault();\n\t\n\t /** Allow paste when event target is editable */\n\t if (event.target.contentEditable != 'true') {\n\t\n\t return;\n\t }\n\t\n\t /** get html pasted data - dirty data */\n\t var data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain');\n\t\n\t /** Temporary DIV that is used to work with childs as arrays item */\n\t var div = editor.draw.node('DIV', '', {}),\n\t cleaner = new editor.sanitizer.init(editor.sanitizer.Config.BASIC),\n\t cleanData,\n\t fragment;\n\t\n\t /** Create fragment, that we paste to range after proccesing */\n\t fragment = document.createDocumentFragment();\n\t\n\t cleanData = cleaner.clean(data);\n\t\n\t div.innerHTML = cleanData;\n\t\n\t var node, lastNode;\n\t\n\t /**\n\t * and fill in fragment\n\t */\n\t while (node = div.firstChild) {\n\t\n\t lastNode = fragment.appendChild(node);\n\t }\n\t\n\t /**\n\t * work with selection and range\n\t */\n\t var selection, range;\n\t\n\t selection = window.getSelection();\n\t\n\t range = selection.getRangeAt(0);\n\t range.deleteContents();\n\t\n\t range.insertNode(fragment);\n\t\n\t /** Preserve the selection */\n\t if (lastNode) {\n\t\n\t range = range.cloneRange();\n\t range.setStartAfter(lastNode);\n\t range.collapse(true);\n\t selection.removeAllRanges();\n\t selection.addRange(range);\n\t }\n\t };\n\t\n\t /**\n\t * Sends all mutations to paste handler\n\t */\n\t callbacks.handleMutationsOnPaste = function (mutations) {\n\t\n\t var self = this;\n\t\n\t /**\n\t * Calling function with context of this function.\n\t * Also, we should sanitize pasted or changed data one time and ignore\n\t * changings which makes sanitize method.\n\t * For that, we need to send Context, MutationObserver.__proto__ that contains\n\t * observer disconnect method.\n\t */\n\t mutations.forEach(function (mutation) {\n\t\n\t editor.content.paste.call(self, mutation);\n\t });\n\t };\n\t\n\t /**\n\t * Clicks on block settings button\n\t */\n\t callbacks.showSettingsButtonClicked = function () {\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/* 12 */\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 * Block with notifications\n\t */\n\t draw.alertsHolder = function () {\n\t\n\t var block = document.createElement('div');\n\t\n\t block.classList.add('ce_notifications-block');\n\t\n\t return block;\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 return draw;\n\t}({});\n\n/***/ },\n/* 13 */\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\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (caret) {\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.tagName == 'INPUT') {\n\t\n\t el.focus();\n\t return;\n\t }\n\t\n\t if (editor.core.isDomNode(nodeToSet)) {\n\t\n\t nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);\n\t }\n\t\n\t var range = document.createRange(),\n\t selection = window.getSelection();\n\t\n\t window.setTimeout(function () {\n\t\n\t range.setStart(nodeToSet, offset);\n\t range.setEnd(nodeToSet, offset);\n\t\n\t selection.removeAllRanges();\n\t selection.addRange(range);\n\t\n\t editor.caret.saveCurrentInputIndex();\n\t }, 20);\n\t };\n\t\n\t /**\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.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 return caret;\n\t}({});\n\n/***/ },\n/* 14 */\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\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (notifications) {\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.send('This action is not available currently', event.type, false);\n\t };\n\t\n\t /**\n\t * Appends notification with different types\n\t * @param message {string} - Error or alert message\n\t * @param type {string} - Type of message notification. Ex: Error, Warning, Danger ...\n\t * @param append {boolean} - can be True or False when notification should be inserted after\n\t */\n\t notifications.send = function (message, type, append) {\n\t\n\t var notification = editor.draw.block('div');\n\t\n\t notification.textContent = message;\n\t notification.classList.add('ce_notification-item', 'ce_notification-' + type, 'flipInX');\n\t\n\t if (!append) {\n\t\n\t editor.nodes.notifications.innerHTML = '';\n\t }\n\t\n\t editor.nodes.notifications.appendChild(notification);\n\t\n\t window.setTimeout(function () {\n\t\n\t notification.remove();\n\t }, 3000);\n\t };\n\t\n\t return notifications;\n\t}({});\n\n/***/ },\n/* 15 */\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\tvar editor = codex.editor;\n\t\n\tmodule.exports = function (parser) {\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/* 16 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Sanitizer\n\t */\n\t\n\tvar janitor = __webpack_require__(17);\n\t\n\tmodule.exports = function (sanitizer) {\n\t\n\t /**\n\t * Basic config\n\t */\n\t var Config = {\n\t\n\t BASIC: {\n\t\n\t tags: {\n\t p: {},\n\t a: {\n\t href: true,\n\t target: '_blank',\n\t rel: 'nofollow'\n\t },\n\t i: {},\n\t b: {},\n\t strong: {},\n\t em: {},\n\t span: {}\n\t }\n\t }\n\t };\n\t\n\t sanitizer.Config = Config;\n\t\n\t sanitizer.init = janitor;\n\t\n\t return sanitizer;\n\t}({});\n\n/***/ },\n/* 17 */\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/******/ ]);\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 43045d00c4b3573b3ca6","/**\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\n var init = function () {\n\n editor.core = require('./modules/core');\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\n };\n\n /**\n * @public\n *\n * holds initial settings\n */\n editor.settings = {\n tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n textareaId: 'codex-editor',\n uploadImagesUrl: '/editor/transport/',\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 textarea : 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 {} userSettings are :\n * - tools [],\n * - textareaId String\n * ...\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.make)\n .then(editor.ui.addTools)\n .then(editor.ui.bindEvents)\n .then(editor.ui.preparePlugins)\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// WEBPACK FOOTER //\n// ./codex.js","/**\n * Codex Editor Core\n *\n * @author Codex Team\n * @version 1.1.2\n */\n\nlet editor = codex.editor;\n\nmodule.exports = (function (core) {\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.uploadImagesUrl) {\n\n editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;\n\n }\n\n editor.nodes.textarea = document.getElementById(userSettings.textareaId || editor.settings.textareaId);\n\n if (typeof editor.nodes.textarea === undefined || editor.nodes.textarea === null) {\n\n reject(Error(\"Textarea wasn't found by ID: #\" + userSettings.textareaId));\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 };\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 * Native Ajax\n */\n core.ajax = function (data) {\n\n if (!data || !data.url) {\n\n return;\n\n }\n\n var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\n successFunction = function () {},\n params = '',\n obj;\n\n data.async = true;\n data.type = data.type || 'GET';\n data.data = data.data || '';\n data['content-type'] = data['content-type'] || 'application/json; charset=utf-8';\n successFunction = data.success || successFunction ;\n\n if (data.type == 'GET' && data.data) {\n\n data.url = /\\?/.test(data.url) ? data.url + '&' + data.data : data.url + '?' + data.data;\n\n } else {\n\n for(obj in data.data) {\n\n params += (obj + '=' + encodeURIComponent(data.data[obj]) + '&');\n\n }\n\n }\n\n if (data.withCredentials) {\n\n XMLHTTP.withCredentials = true;\n\n }\n\n if (data.beforeSend && typeof data.beforeSend == 'function') {\n\n data.beforeSend.call();\n\n }\n\n XMLHTTP.open( data.type, data.url, data.async );\n XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n\n XMLHTTP.onreadystatechange = function () {\n\n if (XMLHTTP.readyState == 4 && XMLHTTP.status == 200) {\n\n successFunction(XMLHTTP.responseText);\n\n }\n\n };\n\n XMLHTTP.send(params);\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 const instancePrefix = 'cdx-script-';\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(instancePrefix + instanceName) ) {\n\n resolve(scriptPath);\n\n }\n\n script = document.createElement('SCRIPT');\n script.async = true;\n script.defer = true;\n script.id = instancePrefix + 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 return core;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/core.js","/**\n * Codex Editor UI module\n *\n * @author Codex Team\n * @version 1.1\n */\n\nlet editor = codex.editor;\n\nmodule.exports = (function (ui) {\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} - highlights covered blocks\n */\n BLOCK_IN_FEED_MODE : 'ce-block--feed-mode',\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.make = function () {\n\n var wrapper,\n toolbar,\n toolbarContent,\n redactor,\n notifications,\n blockButtons,\n blockSettings,\n showSettingsButton,\n showTrashButton,\n toolbox,\n plusButton;\n\n /** Make editor wrapper */\n wrapper = editor.draw.wrapper();\n\n /** Append editor wrapper after initial textarea */\n editor.core.insertAfter(editor.nodes.textarea, wrapper);\n\n /** Append block with notifications to the document */\n notifications = editor.draw.alertsHolder();\n editor.nodes.notifications = document.body.appendChild(notifications);\n\n /** Make toolbar and content-editable redactor */\n toolbar = editor.draw.toolbar();\n toolbarContent = editor.draw.toolbarContent();\n plusButton = editor.draw.plusButton();\n showSettingsButton = editor.draw.settingsButton();\n showTrashButton = editor.toolbar.settings.makeRemoveBlockButton();\n blockSettings = editor.draw.blockSettings();\n blockButtons = editor.draw.blockButtons();\n toolbox = editor.draw.toolbox();\n redactor = editor.draw.redactor();\n\n /** settings */\n var defaultSettings = editor.draw.defaultSettings(),\n pluginSettings = editor.draw.pluginsSettings();\n\n /** Add default and plugins settings */\n blockSettings.appendChild(pluginSettings);\n blockSettings.appendChild(defaultSettings);\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 /** Append plus button */\n toolbarContent.appendChild(plusButton);\n\n /** Appending toolbar tools */\n toolbarContent.appendChild(toolbox);\n\n /** Appending first-level block buttons */\n toolbar.appendChild(blockButtons);\n\n /** Append toolbarContent to toolbar */\n toolbar.appendChild(toolbarContent);\n\n wrapper.appendChild(toolbar);\n\n wrapper.appendChild(redactor);\n\n /** Save created ui-elements to static nodes state */\n editor.nodes.wrapper = wrapper;\n editor.nodes.toolbar = toolbar;\n editor.nodes.plusButton = plusButton;\n editor.nodes.toolbox = toolbox;\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 editor.nodes.redactor = redactor;\n\n /** Make container for inline toolbar */\n editor.ui.makeInlineToolbar();\n\n /** fill in default settings */\n editor.toolbar.settings.addDefaultSettings();\n\n };\n\n ui.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 /**\n * @private\n * Append tools passed in editor.tools\n */\n ui.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) {\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 * Add inline toolbar tools\n */\n editor.ui.addInlineToolbarTools();\n\n\n };\n\n ui.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 underline: {\n icon : 'ce-icon-underline',\n command : 'underline'\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 ui.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 document.addEventListener('keydown', editor.callback.globalKeydown, false );\n\n /** All keydowns on Redactor zone */\n editor.nodes.redactor.addEventListener('keydown', editor.callback.redactorKeyDown, false);\n\n /** All keydowns on Document */\n document.addEventListener('keyup', editor.callback.globalKeyup, false );\n\n /**\n * Mouse click to radactor\n */\n editor.nodes.redactor.addEventListener('click', editor.callback.redactorClicked, false );\n\n /**\n * Clicks to the Plus button\n */\n editor.nodes.plusButton.addEventListener('click', editor.callback.plusButtonClicked, false);\n\n /**\n * Clicks to SETTINGS button in toolbar\n */\n editor.nodes.showSettingsButton.addEventListener('click', editor.callback.showSettingsButtonClicked, false );\n\n /**\n * @deprecated ( but now in use for syncronization );\n * Any redactor changes: keyboard input, mouse cut/paste, drag-n-drop text\n */\n // editor.nodes.redactor.addEventListener('input', editor.callback.redactorInputEvent, false );\n\n /** Bind click listeners on toolbar buttons */\n for (var button in editor.nodes.toolbarButtons) {\n\n editor.nodes.toolbarButtons[button].addEventListener('click', editor.callback.toolbarButtonClicked, false);\n\n }\n\n };\n\n /**\n * Initialize plugins before using\n * Ex. Load scripts or call some internal methods\n * @return Promise\n */\n ui.preparePlugins = function () {\n\n return new Promise(function (resolve, reject) {\n\n let pluginName,\n plugin;\n\n for ( pluginName in editor.tools ) {\n\n plugin = editor.tools[pluginName];\n\n if (typeof plugin.prepare != 'function') {\n\n continue;\n\n }\n\n plugin.prepare(plugin.config || {}).then(function () {\n\n resolve();\n\n }).catch(function (error) {\n\n reject(error);\n\n });\n\n }\n\n });\n\n };\n\n ui.addBlockHandlers = function (block) {\n\n if (!block) return;\n\n /**\n * Block keydowns\n */\n block.addEventListener('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 block.addEventListener('paste', editor.callback.blockPasteCallback, false);\n\n block.addEventListener('mouseup', 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 /** Save all inputs in global variable state */\n editor.state.inputs = redactor.querySelectorAll('[contenteditable], input');\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', 'Расскажите свою историю...');\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 button.addEventListener('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// WEBPACK FOOTER //\n// ./modules/ui.js","/**\n *\n * Codex.Editor Transport Module\n *\n * @author Codex Team\n * @version 1.0\n */\nlet editor = codex.editor;\n\nmodule.exports = (function (transport) {\n\n transport.input = null;\n\n /**\n * @property {Object} arguments - keep plugin settings and defined callbacks\n */\n transport.arguments = null;\n\n transport.prepare = function () {\n\n var input = document.createElement('INPUT');\n\n input.type = 'file';\n input.addEventListener('change', editor.transport.fileSelected);\n\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 this.input = null;\n\n /** Prepare new one */\n this.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 files = input.files,\n formdData = new FormData();\n\n formdData.append('files', files[0], files[0].name);\n\n editor.transport.ajax({\n data : formdData,\n beforeSend : editor.transport.arguments.beforeSend,\n success : editor.transport.arguments.success,\n error : editor.transport.arguments.error\n });\n\n };\n\n /**\n * Use plugin callbacks\n * @protected\n */\n transport.selectAndUpload = function (args) {\n\n this.arguments = args;\n this.input.click();\n\n };\n\n /**\n * Ajax requests module\n * @todo use core.ajax\n */\n transport.ajax = function (params) {\n\n var xhr = new XMLHttpRequest(),\n beforeSend = typeof params.beforeSend == 'function' ? params.beforeSend : function () {},\n success = typeof params.success == 'function' ? params.success : function () {},\n error = typeof params.error == 'function' ? params.error : function () {};\n\n beforeSend();\n\n xhr.open('POST', editor.settings.uploadImagesUrl, true);\n\n xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\n xhr.onload = function () {\n\n if (xhr.status === 200) {\n\n success(xhr.responseText);\n\n } else {\n\n editor.core.log('request error: %o', xhr);\n error();\n\n }\n\n };\n\n xhr.send(params.data);\n this.clearInput();\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\nlet editor = codex.editor;\n\nmodule.exports = (function (renderer) {\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.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 blocksList[index];\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} blockData looks like\n * { header : {\n * text: '',\n * type: 'H3', ...\n * }\n * }\n * @return {object} with type and Element\n */\n renderer.createBlockFromData = function (blockData) {\n\n /** New parser */\n var pluginName = blockData.type,\n cover = blockData.cover;\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 /** New Parser */\n var block = editor.tools[pluginName].render(blockData.data);\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 cover : cover\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.0.2\n */\n\nlet editor = codex.editor;\n\nmodule.exports = (function (saver) {\n\n /**\n * Saves blocks\n * @private\n */\n saver.saveBlocks = function () {\n\n /** Save html content of redactor to memory */\n editor.state.html = editor.nodes.redactor.innerHTML;\n\n /** Empty jsonOutput state */\n editor.state.jsonOutput = [];\n\n Promise.resolve()\n\n .then(function () {\n\n return editor.nodes.redactor.childNodes;\n\n })\n /** Making a sequence from separate blocks */\n .then(editor.saver.makeQueue)\n\n .then(function () {\n // editor.nodes.textarea.innerHTML = editor.state.html;\n })\n\n .catch( function (error) {\n\n editor.core.log(error);\n\n });\n\n };\n\n saver.makeQueue = function (blocks) {\n\n var queue = Promise.resolve();\n\n for(var index = 0; index < blocks.length; index++) {\n\n /** Add node to sequence at specified index */\n editor.saver.getBlockData(queue, blocks, index);\n\n }\n\n };\n\n /** Gets every block and makes From Data */\n saver.getBlockData = function (queue, blocks, index) {\n\n queue.then(function () {\n\n return editor.saver.getNodeAsync(blocks, index);\n\n })\n\n .then(editor.saver.makeFormDataFromBlocks);\n\n };\n\n\n /**\n * Asynchronously returns block data from blocksList by index\n * @return Promise to node\n */\n saver.getNodeAsync = function (blocksList, index) {\n\n return Promise.resolve().then(function () {\n\n return blocksList[index];\n\n });\n\n };\n\n saver.makeFormDataFromBlocks = function (block) {\n\n var pluginName = block.dataset.tool;\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].save != 'function') {\n\n throw Error(`Plugin «${pluginName}» must have save method`);\n\n }\n\n /** Result saver */\n var blockContent = block.childNodes[0],\n pluginsContent = blockContent.childNodes[0],\n savedData = editor.tools[pluginName].save(pluginsContent),\n output;\n\n\n output = {\n type: pluginName,\n data: savedData\n };\n\n if (editor.tools[pluginName].validate) {\n\n var result = editor.tools[pluginName].validate(savedData);\n\n /**\n * Do not allow invalid data\n */\n if (!result)\n return;\n\n }\n\n /** Marks Blocks that will be in main page */\n output.cover = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\n editor.state.jsonOutput.push(output);\n\n };\n\n return saver;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/saver.js","/**\n * Codex Editor Content Module\n * Works with DOM\n *\n * @author Codex Team\n * @version 1.3.11\n */\nlet editor = codex.editor;\n\nmodule.exports = (function (content) {\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 * 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 * @deprecated\n */\n content.getNodeFocused = function () {\n\n var selection = window.getSelection(),\n focused;\n\n if (selection.anchorNode === null) {\n\n return null;\n\n }\n\n if ( selection.anchorNode.nodeType == editor.core.nodeTypes.TAG ) {\n\n focused = selection.anchorNode;\n\n } else {\n\n focused = selection.focusNode.parentElement;\n\n }\n\n if ( !editor.parser.isFirstLevelBlock(focused) ) {\n\n /** Iterate with parent nodes to find first-level*/\n var parent = focused.parentNode;\n\n while (parent && !editor.parser.isFirstLevelBlock(parent)) {\n\n parent = parent.parentNode;\n\n }\n\n focused = parent;\n\n }\n\n if (focused != editor.nodes.redactor) {\n\n return focused;\n\n }\n\n return null;\n\n };\n\n /**\n * Appends background to the block\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 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 * @private\n *\n * Finds first-level block\n * @param {Element} node - selected or clicked in redactors area node\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 * 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 this.currentNode = this.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 /**\n * Check is this block was in feed\n * If true, than set switched block also covered\n */\n if (targetBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE)) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\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 * @private\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 cover = blockData.cover,\n isStretched = blockData.stretched;\n\n var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched);\n\n if (cover === true) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\n }\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 var newBlockComposed = editor.content.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 * @private\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 */\n content.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 */\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 * @private\n * @param {Int} inputIndex - target input index\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 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 * @private\n *\n * Callback for HTML Mutations\n * @param {Array} mutation - Mutation Record\n */\n content.paste = function (mutation) {\n\n var workingNode = editor.content.currentNode,\n tool = workingNode.dataset.tool;\n\n if (editor.tools[tool].allowedToPaste) {\n\n editor.content.sanitize.call(this, mutation.target);\n\n } else {\n\n editor.content.pasteTextContent(mutation.addedNodes);\n\n }\n\n };\n\n /**\n * @private\n *\n * gets only text/plain content of node\n * @param {Element} target - HTML node\n */\n content.pasteTextContent = function (nodes) {\n\n var node = nodes[0],\n textNode;\n\n if (!node) {\n\n return;\n\n }\n\n if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\n textNode = document.createTextNode(node);\n\n } else {\n\n textNode = document.createTextNode(node.textContent);\n\n }\n\n if (editor.core.isDomNode(node)) {\n\n node.parentNode.replaceChild(textNode, node);\n\n }\n\n };\n\n /**\n * @private\n *\n * Sanitizes HTML content\n * @param {Element} target - inserted element\n * @uses Sanitize library html-janitor\n */\n content.sanitize = function (target) {\n\n if (!target) {\n\n return;\n\n }\n\n var node = target[0];\n\n if (!node) {\n\n return;\n\n }\n\n /**\n * Disconnect Observer\n * hierarchy of function calls inherits context of observer\n */\n this.disconnect();\n\n /**\n * Don't sanitize text node\n */\n if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\n return;\n\n }\n\n /**\n * Clear dirty content\n */\n var cleaner = editor.sanitizer.init(editor.satinizer.Config.BASIC),\n clean = cleaner.clean(target.outerHTML);\n\n var div = editor.draw.node('DIV', [], { innerHTML: clean });\n\n node.replaceWith(div.childNodes[0]);\n\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] htmlString - html content as string\n * @return {string} - html content as string\n */\n content.wrapTextWithParagraphs = function (htmlString) {\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 = htmlString;\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 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\nlet editor = codex.editor;\n\nmodule.exports = (function (toolbar) {\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 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// WEBPACK FOOTER //\n// ./modules/toolbar/toolbar.js","/**\n * Toolbar settings\n *\n * @version 1.0.4\n */\n\nlet editor = codex.editor;\n\nmodule.exports = (function (settings) {\n\n settings.opened = false;\n\n settings.setting = null;\n settings.actions = null;\n\n settings.cover = 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 editor.core.log(`Plugin «${toolType}» has no settings`, 'warn');\n // editor.nodes.pluginSettings.innerHTML = `Плагин «${toolType}» не имеет настроек`;\n\n } else {\n\n /**\n * Draw settings block\n */\n var settingsBlock = editor.tools[toolType].makeSettings();\n\n editor.nodes.pluginSettings.appendChild(settingsBlock);\n\n }\n\n /** Open settings block */\n editor.nodes.blockSettings.classList.add('opened');\n editor.toolbar.settings.addDefaultSettings();\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 * This function adds default core settings\n */\n settings.addDefaultSettings = function () {\n\n /** list of default settings */\n var feedModeToggler;\n\n /** Clear block and append initialized settings */\n editor.nodes.defaultSettings.innerHTML = '';\n\n\n /** Init all default setting buttons */\n feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();\n\n /**\n * Fill defaultSettings\n */\n\n /**\n * Button that enables/disables Feed-mode\n * Feed-mode means that block will be showed in articles-feed like cover\n */\n editor.nodes.defaultSettings.appendChild(feedModeToggler);\n\n };\n\n /**\n * Cover setting.\n * This tune highlights block, so that it may be used for showing target block on main page\n * Draw different setting when block is marked for main page\n * If TRUE, then we show button that removes this selection\n * Also defined setting \"Click\" events will be listened and have separate callbacks\n *\n * @return {Element} node/button that we place in default settings block\n */\n settings.makeFeedModeToggler = function () {\n\n var isFeedModeActivated = editor.toolbar.settings.isFeedModeActivated(),\n setting,\n data;\n\n if (!isFeedModeActivated) {\n\n data = {\n innerHTML : '<i class=\"ce-icon-newspaper\"></i>Вывести в ленте'\n };\n\n } else {\n\n data = {\n innerHTML : '<i class=\"ce-icon-newspaper\"></i>Не выводить в ленте'\n };\n\n }\n\n setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\n setting.addEventListener('click', editor.toolbar.settings.updateFeedMode, false);\n\n return setting;\n\n };\n\n /**\n * Updates Feed-mode\n */\n settings.updateFeedMode = function () {\n\n var currentNode = editor.content.currentNode;\n\n currentNode.classList.toggle(editor.ui.className.BLOCK_IN_FEED_MODE);\n\n editor.toolbar.settings.close();\n\n };\n\n settings.isFeedModeActivated = function () {\n\n var currentBlock = editor.content.currentNode;\n\n if (currentBlock) {\n\n return currentBlock.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\n } else {\n\n return false;\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 settingButton.addEventListener('click', editor.toolbar.settings.removeButtonClicked, false);\n\n confirmAction.addEventListener('click', editor.toolbar.settings.confirmRemovingRequest, false);\n\n cancelAction.addEventListener('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// 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\nlet editor = codex.editor;\n\nmodule.exports = (function (inline) {\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 (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 action.addEventListener('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// 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\nlet editor = codex.editor;\n\nmodule.exports = (function (toolbox) {\n\n toolbox.opened = false;\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 /** 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 /** Makes toolbox disapear */\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 };\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;\n visibleTool = tools[nextToolIndex];\n\n while (!editor.tools[visibleTool].displayInToolbox) {\n\n nextToolIndex++;\n visibleTool = tools[nextToolIndex];\n\n if ( nextToolIndex == tools.length ) {\n\n nextToolIndex = 0;\n visibleTool = tools[nextToolIndex];\n\n }\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 * Codex Editor callbacks module\n *\n * @author Codex Team\n * @version 1.3.7\n */\nlet editor = codex.editor;\n\nmodule.exports = (function (callbacks) {\n\n callbacks.globalKeydown = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.ENTER : editor.callback.enterKeyPressed(event); break;\n }\n\n };\n\n callbacks.redactorKeyDown = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.TAB : editor.callback.tabKeyPressed(event); break;\n case editor.core.keys.ENTER : editor.callback.enterKeyPressedOnRedactorZone(event); break;\n case editor.core.keys.ESC : editor.callback.escapeKeyPressed(event); break;\n default : editor.callback.defaultKeyPressed(event); break;\n }\n\n };\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 : editor.callback.arrowKeyPressed(event); break;\n }\n\n };\n\n callbacks.tabKeyPressed = function (event) {\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 event.preventDefault();\n\n };\n\n /**\n * @param {Event} event\n */\n callbacks.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 editor.callback.enterPressedOnBlock();\n\n }\n\n };\n\n /**\n * ENTER key handler\n * Makes new paragraph block\n */\n callbacks.enterKeyPressedOnRedactorZone = 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 callbacks.escapeKeyPressed = 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 */\n callbacks.arrowKeyPressed = function () {\n\n editor.content.workingNodeChanged();\n\n /* Closing toolbar */\n editor.toolbar.close();\n editor.toolbar.move();\n\n };\n\n /**\n * @param {Event} event\n */\n callbacks.defaultKeyPressed = 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 callbacks.redactorClicked = function (event) {\n\n callbacks.detectWhenClickedOnFirstLevelBlockArea();\n\n editor.content.workingNodeChanged(event.target);\n\n editor.ui.saveInputs();\n\n var selectedText = editor.toolbar.inline.getSelectionText(),\n firstLevelBlock;\n\n /**\n * If selection range took off, then we hide inline toolbar\n */\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 /**\n * @todo Refactor\n */\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 /**\n * Move toolbar to the right position and open\n */\n editor.toolbar.move();\n editor.toolbar.open();\n\n } else {\n\n /**\n * Move toolbar to the new position and open\n */\n editor.toolbar.move();\n editor.toolbar.open();\n\n /** Close all panels */\n editor.toolbar.settings.close();\n editor.toolbar.toolbox.close();\n\n }\n\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 /** Mark current block */\n editor.content.markBlock();\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 * 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 callbacks.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 ? false : true;\n\n }\n\n };\n\n /**\n * Toolbar button click handler\n * @param this - cursor to the button\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 /** Show or Hide toolbox when plus button is clicked */\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 callbacks.blockKeydown = function (event) {\n\n let block = this; // event.target input\n\n switch (event.keyCode) {\n\n case editor.core.keys.DOWN:\n case editor.core.keys.RIGHT:\n editor.callback.blockRightOrDownArrowPressed();\n break;\n\n case editor.core.keys.BACKSPACE:\n editor.callback.backspacePressed(block, event);\n break;\n\n case editor.core.keys.UP:\n case editor.core.keys.LEFT:\n editor.callback.blockLeftOrUpArrowPressed();\n break;\n\n }\n\n };\n\n /**\n * RIGHT or DOWN keydowns on block\n */\n callbacks.blockRightOrDownArrowPressed = function () {\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 callbacks.blockLeftOrUpArrowPressed = function () {\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 * Callback for enter key pressing in first-level block area\n * @param {Event} event\n */\n callbacks.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 callbacks.backspacePressed = function (block, event) {\n\n var currentInputIndex = editor.caret.getCurrentInputIndex(),\n range,\n selectionLength,\n firstLevelBlocksCount;\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 * This method is used to observe pasted dirty data.\n *\n * Mutation handlers send to separate observers each mutation (added, changed and so on), which will be\n * passed from handler that sanitizes and replaces data.\n *\n * Probably won't be used\n *\n * @deprecated\n *\n * @param event\n * @private\n */\n callbacks._blockPasteCallback = function () {\n\n var currentInputIndex = editor.caret.getCurrentInputIndex();\n\n /**\n * create an observer instance\n */\n var observer = new MutationObserver(editor.callback.handleMutationsOnPaste);\n\n /**\n * configuration of the observer:\n */\n var config = {\n attributes: true,\n childList: false,\n characterData: false,\n subtree : true\n };\n\n // pass in the target node, as well as the observer options\n observer.observe(editor.state.inputs[currentInputIndex], config);\n\n };\n\n /**\n * This method prevents default behaviour.\n *\n * 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 * @param event\n */\n callbacks.blockPasteCallback = function (event) {\n\n /** Prevent default behaviour */\n event.preventDefault();\n\n /** Allow paste when event target is editable */\n if (event.target.contentEditable != 'true') {\n\n return;\n\n }\n\n /** get html pasted data - dirty data */\n var data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain');\n\n /** Temporary DIV that is used to work with childs as arrays item */\n var div = editor.draw.node('DIV', '', {}),\n cleaner = new editor.sanitizer.init(editor.sanitizer.Config.BASIC),\n cleanData,\n fragment;\n\n /** Create fragment, that we paste to range after proccesing */\n fragment = document.createDocumentFragment();\n\n cleanData = cleaner.clean(data);\n\n div.innerHTML = cleanData;\n\n var node, lastNode;\n\n /**\n * and fill in fragment\n */\n while (( node = div.firstChild) ) {\n\n lastNode = fragment.appendChild(node);\n\n }\n\n /**\n * work with selection and range\n */\n var selection, range;\n\n selection = window.getSelection();\n\n range = selection.getRangeAt(0);\n range.deleteContents();\n\n range.insertNode(fragment);\n\n /** Preserve the selection */\n if (lastNode) {\n\n range = range.cloneRange();\n range.setStartAfter(lastNode);\n range.collapse(true);\n selection.removeAllRanges();\n selection.addRange(range);\n\n }\n\n };\n\n /**\n * Sends all mutations to paste handler\n */\n callbacks.handleMutationsOnPaste = function (mutations) {\n\n var self = this;\n\n /**\n * Calling function with context of this function.\n * Also, we should sanitize pasted or changed data one time and ignore\n * changings which makes sanitize method.\n * For that, we need to send Context, MutationObserver.__proto__ that contains\n * observer disconnect method.\n */\n mutations.forEach(function (mutation) {\n\n editor.content.paste.call(self, mutation);\n\n });\n\n };\n\n /**\n * Clicks on block settings button\n */\n callbacks.showSettingsButtonClicked = function () {\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 * Block with notifications\n */\n draw.alertsHolder = function () {\n\n var block = document.createElement('div');\n\n block.classList.add('ce_notifications-block');\n\n return block;\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 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 */\nlet editor = codex.editor;\n\nmodule.exports = (function (caret) {\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.tagName == 'INPUT') {\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.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 return caret;\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 */\nlet editor = codex.editor;\n\nmodule.exports = (function (notifications) {\n\n /**\n * Error notificator. Shows block with message\n * @protected\n */\n notifications.errorThrown = function (errorMsg, event) {\n\n editor.notifications.send('This action is not available currently', event.type, false);\n\n };\n\n /**\n * Appends notification with different types\n * @param message {string} - Error or alert message\n * @param type {string} - Type of message notification. Ex: Error, Warning, Danger ...\n * @param append {boolean} - can be True or False when notification should be inserted after\n */\n notifications.send = function (message, type, append) {\n\n var notification = editor.draw.block('div');\n\n notification.textContent = message;\n notification.classList.add('ce_notification-item', 'ce_notification-' + type, 'flipInX');\n\n if (!append) {\n\n editor.nodes.notifications.innerHTML = '';\n\n }\n\n editor.nodes.notifications.appendChild(notification);\n\n window.setTimeout(function () {\n\n notification.remove();\n\n }, 3000);\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 */\nlet editor = codex.editor;\n\nmodule.exports = (function (parser) {\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\nvar janitor = require('html-janitor');\n\nmodule.exports = (function (sanitizer) {\n\n /**\n * Basic config\n */\n var Config = {\n\n BASIC : {\n\n tags: {\n p: {},\n a: {\n href: true,\n target: '_blank',\n rel: 'nofollow'\n },\n i: {},\n b: {},\n strong: {},\n em: {},\n span: {}\n }\n }\n };\n\n sanitizer.Config = Config;\n\n sanitizer.init = janitor;\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 = 17\n// module chunks = 0"],"sourceRoot":""} |