diff --git a/codex-editor.css b/codex-editor.css index 27636f80..1fb54f95 100644 --- a/codex-editor.css +++ b/codex-editor.css @@ -112,6 +112,7 @@ margin-right: 17px; border-radius: 16px; text-align: center; + vertical-align: top; cursor: pointer; font-size: 14px; diff --git a/codex-editor.js b/codex-editor.js index d4ca5e50..fcba24c0 100644 --- a/codex-editor.js +++ b/codex-editor.js @@ -1,3 +1,3 @@ -var codex=codex||{};codex.editor=function(e){function t(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return e[o].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";e.exports=function(e){e.version="1.5.2",e.scriptPrefix="cdx-script-";var t=function(){e.core=n(1),e.tools=n(2),e.ui=n(3),e.transport=n(4),e.renderer=n(5),e.saver=n(6),e.content=n(7),e.toolbar=n(8),e.callback=n(12),e.draw=n(13),e.caret=n(14),e.notifications=n(15),e.parser=n(16),e.sanitizer=n(17),e.anchors=n(19),e.listeners=n(20),e.destroyer=n(21),e.paste=n(22)};return e.settings={tools:["paragraph","header","picture","list","quote","code","twitter","instagram","smile"],textareaId:"codex-editor",uploadImagesUrl:"/editor/transport/",initialBlockPlugin:"paragraph"},e.nodes={textarea:null,wrapper:null,toolbar:null,inlineToolbar:{wrapper:null,buttons:null,actions:null},toolbox:null,notifications:null,plusButton:null,showSettingsButton:null,showTrashButton:null,blockSettings:null,pluginSettings:null,defaultSettings:null,toolbarButtons:{},redactor:null},e.state={jsonOutput:[],blocks:[],inputs:[]},e.tools={},e.start=function(n){t(),e.core.prepare(n).then(e.ui.make).then(e.ui.addTools).then(e.ui.bindEvents).then(e.tools.prepare).then(e.paste.prepare).then(e.transport.prepare).then(e.renderer.makeBlocksFromData).then(e.ui.saveInputs).catch(function(t){e.core.log("Initialization failed with error: %o","warn",t)})},e}({})},function(e,t){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};e.exports=function(e){var t=codex.editor;return e.prepare=function(e){return new Promise(function(o,r){e&&(t.settings.tools=e.tools||t.settings.tools),e.data&&(t.state.blocks=e.data),e.initialBlockPlugin&&(t.settings.initialBlockPlugin=e.initialBlockPlugin),e.uploadImagesUrl&&(t.settings.uploadImagesUrl=e.uploadImagesUrl),t.hideToolbar=e.hideToolbar,t.nodes.textarea=document.getElementById(e.textareaId||t.settings.textareaId),void 0===n(t.nodes.textarea)||null===t.nodes.textarea?r(Error("Textarea wasn't found by ID: #"+e.textareaId)):o()})},e.log=function(e,t,n){t=t||"log",n?e="[codex-editor]: "+e:(n=e||"undefined",e="[codex-editor]: %o");try{"console"in window&&window.console[t]&&(n?window.console[t](e,n):window.console[t](e))}catch(e){}},e.insertAfter=function(e,t){e.parentNode.insertBefore(t,e.nextSibling)},e.nodeTypes={TAG:1,TEXT:3,COMMENT:8},e.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},e.isDomNode=function(e){return e&&"object"===("undefined"==typeof e?"undefined":n(e))&&e.nodeType&&e.nodeType==this.nodeTypes.TAG},e.isEmpty=function(e){return 0===Object.keys(e).length},e.ajax=function(e){if(e&&e.url){var t,n=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),o=function(){},r="";if(e.async=!0,e.type=e.type||"GET",e.data=e.data||"",e["content-type"]=e["content-type"]||"application/json; charset=utf-8",o=e.success||o,"GET"==e.type&&e.data)e.url=/\?/.test(e.url)?e.url+"&"+e.data:e.url+"?"+e.data;else for(t in e.data)r+=t+"="+encodeURIComponent(e.data[t])+"&";e.withCredentials&&(n.withCredentials=!0),e.beforeSend&&"function"==typeof e.beforeSend&&e.beforeSend.call(),n.open(e.type,e.url,e.async),n.setRequestHeader("X-Requested-With","XMLHttpRequest"),n.setRequestHeader("Content-type","application/x-www-form-urlencoded"),n.onreadystatechange=function(){4==n.readyState&&200==n.status&&o(n.responseText)},n.send(r)}},e.importScript=function(e,n){return new Promise(function(o,r){var i=void 0;n?document.getElementById(t.scriptPrefix+n)&&o(e):r("Instance name is missed"),i=document.createElement("SCRIPT"),i.async=!0,i.defer=!0,i.id=t.scriptPrefix+n,i.onload=function(){o(e)},i.onerror=function(){r(e)},i.src=e,document.head.appendChild(i)})},e}({})},function(e,t){"use strict";e.exports=function(){function e(){return new Promise(function(e,o){Promise.resolve().then(function(){var t=[],o=n.tools;for(var r in o){var i=o[r];i.prepare&&"function"!=typeof i.prepare||!i.prepare||t.push(i)}return t.length||e(),t}).then(t).then(function(){n.core.log("Plugins loaded","info"),e()}).catch(function(e){o(e)})})}function t(e){return new Promise(function(t){e.reduce(function(r,i,a){return r.then(function(){return new Promise(function(r){o(i).then(r).then(function(){i.available=!0}).catch(function(e){n.core.log("Plugin «"+i.type+"» was not loaded. Preparation failed because %o","warn",e),i.available=!1,i.loadingMessage=e,r()}).then(function(){a==e.length-1&&t()})})})},Promise.resolve())})}var n=codex.editor,o=function(e){return e.prepare(e.config||{})};return{prepare:e}}()},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.className={BLOCK_CLASSNAME:"ce-block",BLOCK_CONTENT:"ce-block__content",BLOCK_STRETCHED:"ce-block--stretched",BLOCK_HIGHLIGHTED:"ce-block--focused",BLOCK_IN_FEED_MODE:"ce-block--feed-mode",BLOCK_WITH_ANCHOR:"ce-block--anchor",SETTINGS_ITEM:"ce-settings__item"},e.make=function(){var e,n,o,r,i,a,s,c,l,d;e=t.draw.wrapper(),t.core.insertAfter(t.nodes.textarea,e),t.notifications.createHolder(),n=t.draw.toolbar(),o=t.draw.toolbarContent(),d=t.draw.plusButton(),s=t.draw.settingsButton(),c=t.toolbar.settings.makeRemoveBlockButton(),a=t.draw.blockSettings(),i=t.draw.blockButtons(),l=t.draw.toolbox(),r=t.draw.redactor();var u=t.draw.defaultSettings(),p=t.draw.pluginsSettings();a.appendChild(p),a.appendChild(u),i.appendChild(s),i.appendChild(c),i.appendChild(a),o.appendChild(d),o.appendChild(l),n.appendChild(i),n.appendChild(o),e.appendChild(n),e.appendChild(r),t.nodes.wrapper=e,t.nodes.toolbar=n,t.nodes.plusButton=d,t.nodes.toolbox=l,t.nodes.blockSettings=a,t.nodes.pluginSettings=p,t.nodes.defaultSettings=u,t.nodes.showSettingsButton=s,t.nodes.showTrashButton=c,t.nodes.redactor=r,t.ui.makeInlineToolbar(),t.toolbar.settings.addDefaultSettings()},e.makeInlineToolbar=function(){var e=t.draw.inlineToolbar();t.nodes.inlineToolbar.wrapper=e,t.nodes.inlineToolbar.buttons=t.draw.inlineToolbarButtons(),t.nodes.inlineToolbar.actions=t.draw.inlineToolbarActions(),t.nodes.inlineToolbar.wrapper.appendChild(t.nodes.inlineToolbar.buttons),t.nodes.inlineToolbar.wrapper.appendChild(t.nodes.inlineToolbar.actions),t.nodes.wrapper.appendChild(t.nodes.inlineToolbar.wrapper)},e.addTools=function(){var e,n,o;for(n in t.settings.tools)e=t.settings.tools[n],t.tools[n]=e,e.iconClassname||!e.displayInToolbox?"function"==typeof e.render?e.displayInToolbox&&(o=t.draw.toolbarButton(n,e.iconClassname),t.nodes.toolbox.appendChild(o),t.nodes.toolbarButtons[n]=o):t.core.log("render method missed. Tool %o skipped","warn",n):t.core.log("Toolbar icon classname missed. Tool %o skipped","warn",n);t.ui.addInlineToolbarTools()},e.addInlineToolbarTools=function(){var e,n,o={bold:{icon:"ce-icon-bold",command:"bold"},italic:{icon:"ce-icon-italic",command:"italic"},underline:{icon:"ce-icon-underline",command:"underline"},link:{icon:"ce-icon-link",command:"createLink"}};for(var r in o)n=o[r],e=t.draw.toolbarButtonInline(r,n.icon),t.nodes.inlineToolbar.buttons.appendChild(e),t.ui.setInlineToolbarButtonBehaviour(e,n.command)},e.bindEvents=function(){t.core.log("ui.bindEvents fired","info"),t.listeners.add(document,"keydown",t.callback.globalKeydown,!1),t.listeners.add(t.nodes.redactor,"keydown",t.callback.redactorKeyDown,!1),t.listeners.add(document,"keyup",t.callback.globalKeyup,!1),t.listeners.add(t.nodes.redactor,"click",t.callback.redactorClicked,!1),t.listeners.add(t.nodes.plusButton,"click",t.callback.plusButtonClicked,!1),t.listeners.add(t.nodes.showSettingsButton,"click",t.callback.showSettingsButtonClicked,!1);for(var e in t.nodes.toolbarButtons)t.listeners.add(t.nodes.toolbarButtons[e],"click",t.callback.toolbarButtonClicked,!1)},e.addBlockHandlers=function(e){e&&(t.listeners.add(e,"keydown",t.callback.blockKeydown,!1),t.listeners.add(e,"paste",t.callback.blockPasteCallback,!1),t.listeners.add(e,"mouseup",t.toolbar.inline.show,!1))},e.saveInputs=function(){var e=t.nodes.redactor;t.state.inputs=e.querySelectorAll("[contenteditable], input")},e.addInitialBlock=function(){var e,n=t.settings.initialBlockPlugin;return t.tools[n]?(e=t.tools[n].render(),e.setAttribute("data-placeholder","Расскажите свою историю..."),t.content.insertBlock({type:n,block:e}),void t.content.workingNodeChanged(e)):void t.core.log("Plugin %o was not implemented and can't be used as initial block","warn",n)},e.setInlineToolbarButtonBehaviour=function(e,n){t.listeners.add(e,"mousedown",function(e){t.toolbar.inline.toolClicked(e,n)},!1)},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.input=null,e.arguments=null,e.prepare=function(){var e=document.createElement("INPUT");e.type="file",t.listeners.add(e,"change",t.transport.fileSelected),t.transport.input=e},e.clearInput=function(){this.input=null,this.prepare()},e.fileSelected=function(){var e=this,n=e.files,o=new FormData;o.append("files",n[0],n[0].name),t.transport.ajax({data:o,beforeSend:t.transport.arguments.beforeSend,success:t.transport.arguments.success,error:t.transport.arguments.error})},e.selectAndUpload=function(e){this.arguments=e,this.input.click()},e.ajax=function(e){var n=new XMLHttpRequest,o="function"==typeof e.beforeSend?e.beforeSend:function(){},r="function"==typeof e.success?e.success:function(){},i="function"==typeof e.error?e.error:function(){};o(),n.open("POST",t.settings.uploadImagesUrl,!0),n.setRequestHeader("X-Requested-With","XMLHttpRequest"),n.onload=function(){200===n.status?r(n.responseText):(t.core.log("request error: %o",n),i())},n.send(e.data),this.clearInput()},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.makeBlocksFromData=function(){return t.core.isEmpty(t.state.blocks)||!t.state.blocks.items.length?void t.ui.addInitialBlock():void Promise.resolve().then(function(){return t.state.blocks}).then(t.renderer.appendBlocks).catch(function(e){t.core.log("Error while parsing JSON: %o","error",e)})},e.appendBlocks=function(e){for(var n=e.items,o=Promise.resolve(),r=0;rНе выводить в ленте'}:{innerHTML:'Вывести в ленте'},e=t.draw.node("DIV",t.ui.className.SETTINGS_ITEM,n),t.listeners.add(e,"click",t.toolbar.settings.updateFeedMode,!1),e},e.updateFeedMode=function(){var e=t.content.currentNode;e.classList.toggle(t.ui.className.BLOCK_IN_FEED_MODE),t.toolbar.settings.close()},e.isFeedModeActivated=function(){var e=t.content.currentNode;return!!e&&e.classList.contains(t.ui.className.BLOCK_IN_FEED_MODE)},e.makeAnchorInput=function(){var e=t.draw.node("div","ce-settings__anchor-wrapper ce-settings__item",{}),n=t.draw.node("i","ce-settings__anchor-hash",{}),o=t.draw.node("input","ce-settings__anchor-input",{placeholder:"Якорь"});return t.listeners.add(o,"keydown",t.anchors.keyDownOnAnchorInput),t.listeners.add(o,"keyup",t.anchors.keyUpOnAnchorInput),t.listeners.add(o,"input",t.anchors.anchorChanged),t.listeners.add(o,"blur",t.anchors.anchorChanged),e.appendChild(n),e.appendChild(o),t.anchors.input=o,e},e.makeRemoveBlockButton=function(){var e=t.draw.node("SPAN","ce-toolbar__remove-btn",{}),n=t.draw.node("SPAN","ce-toolbar__remove-setting",{innerHTML:''}),o=t.draw.node("DIV","ce-toolbar__remove-confirmation",{}),r=t.draw.node("DIV","ce-toolbar__remove-confirm",{textContent:"Удалить блок"}),i=t.draw.node("DIV","ce-toolbar__remove-cancel",{textContent:"Отмена"});return t.listeners.add(n,"click",t.toolbar.settings.removeButtonClicked,!1),t.listeners.add(r,"click",t.toolbar.settings.confirmRemovingRequest,!1),t.listeners.add(i,"click",t.toolbar.settings.cancelRemovingRequest,!1),o.appendChild(r),o.appendChild(i),e.appendChild(n),e.appendChild(o),t.toolbar.settings.setting=n,t.toolbar.settings.actions=o,e},e.removeButtonClicked=function(){var e=t.toolbar.settings.actions;e.classList.contains("opened")?t.toolbar.settings.hideRemoveActions():t.toolbar.settings.showRemoveActions(),t.toolbar.toolbox.close(),t.toolbar.settings.close()},e.cancelRemovingRequest=function(){t.toolbar.settings.actions.classList.remove("opened")},e.confirmRemovingRequest=function(){var e,n=t.content.currentNode;n.remove(),e=t.nodes.redactor.childNodes.length,0===e&&(t.content.currentNode=null,t.ui.addInitialBlock()),t.ui.saveInputs(),t.toolbar.close()},e.showRemoveActions=function(){t.toolbar.settings.actions.classList.add("opened")},e.hideRemoveActions=function(){t.toolbar.settings.actions.classList.remove("opened")},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;e.buttonsOpened=null,e.actionsOpened=null,e.wrappersOffset=null,e.storedSelection=null,e.show=function(){var n,o=t.content.currentNode,r=o.dataset.tool;if(n=t.tools[r],n.showInlineToolbar){var i=e.getSelectionText(),a=t.nodes.inlineToolbar.wrapper;i.length>0&&(t.toolbar.inline.move(),a.classList.add("opened"),t.toolbar.inline.showButtons())}},e.close=function(){var e=t.nodes.inlineToolbar.wrapper;e.classList.remove("opened")},e.move=function(){this.wrappersOffset||(this.wrappersOffset=this.getWrappersOffset());var e,n,o=this.getSelectionCoords(),r=0,i=t.nodes.inlineToolbar.wrapper;0===i.offsetHeight&&(r=40),e=o.x-this.wrappersOffset.left,n=o.y+window.scrollY-this.wrappersOffset.top-r-i.offsetHeight,i.style.transform="translate3D("+Math.floor(e)+"px, "+Math.floor(n)+"px, 0)",t.toolbar.inline.closeButtons(),t.toolbar.inline.closeAction()},e.toolClicked=function(e,n){switch(n){case"createLink":t.toolbar.inline.createLinkAction(e,n);break;default:t.toolbar.inline.defaultToolAction(n)}t.nodes.inlineToolbar.buttons.childNodes.forEach(t.toolbar.inline.hightlight)},e.getWrappersOffset=function(){var e=t.nodes.wrapper,n=this.getOffset(e);return this.wrappersOffset=n,n},e.getOffset=function(e){for(var t=0,n=0;e&&!isNaN(e.offsetLeft)&&!isNaN(e.offsetTop);)t+=e.offsetLeft+e.clientLeft,n+=e.offsetTop+e.clientTop,e=e.offsetParent;return{top:n,left:t}},e.getSelectionCoords=function(){var e,t=document.selection,n=0,o=0;if(t)"Control"!=t.type&&(e=t.createRange(),e.collapse(!0),n=e.boundingLeft,o=e.boundingTop);else if(window.getSelection&&(t=window.getSelection(),t.rangeCount&&(e=t.getRangeAt(0).cloneRange(),e.getClientRects))){e.collapse(!0);var r=e.getClientRects()[0];if(!r)return;n=r.left,o=r.top}return{x:n,y:o}},e.getSelectionText=function(){var e="";return window.getSelection&&(e=window.getSelection().toString()),e},e.showButtons=function(){var e=t.nodes.inlineToolbar.buttons;e.classList.add("opened"),t.toolbar.inline.buttonsOpened=!0,t.nodes.inlineToolbar.buttons.childNodes.forEach(t.toolbar.inline.hightlight)},e.closeButtons=function(){var e=t.nodes.inlineToolbar.buttons;e.classList.remove("opened"),t.toolbar.inline.buttonsOpened=!1},e.showActions=function(){var e=t.nodes.inlineToolbar.actions;e.classList.add("opened"),t.toolbar.inline.actionsOpened=!0},e.closeAction=function(){var e=t.nodes.inlineToolbar.actions;e.innerHTML="",e.classList.remove("opened"),t.toolbar.inline.actionsOpened=!1};var n=function(e){if(e.keyCode==t.core.keys.ENTER){var n=t.content.currentNode,o=t.toolbar.inline.storedSelection;t.toolbar.inline.restoreSelection(n,o),t.toolbar.inline.setAnchor(this.value),e.preventDefault(),e.stopImmediatePropagation(),t.toolbar.inline.clearRange()}};return e.createLinkAction=function(e){var o=this.isLinkActive(),r=t.content.currentNode,i=t.toolbar.inline.saveSelection(r);if(t.toolbar.inline.storedSelection=i,o)t.toolbar.inline.restoreSelection(r,i),t.toolbar.inline.defaultToolAction("unlink");else{var a=t.draw.inputForLink();t.nodes.inlineToolbar.actions.appendChild(a),t.toolbar.inline.closeButtons(),t.toolbar.inline.showActions(),a.focus(),e.preventDefault(),t.listeners.add(a,"keydown",n,!1)}},e.isLinkActive=function(){var e=!1;return t.nodes.inlineToolbar.buttons.childNodes.forEach(function(t){var n=t.dataset.type;"link"==n&&t.classList.contains("hightlighted")&&(e=!0)}),e},e.defaultToolAction=function(e){document.execCommand(e,!1,null)},e.setAnchor=function(e){document.execCommand("createLink",!1,e),t.toolbar.inline.closeAction()},e.saveSelection=function(e){var t,n=window.getSelection().getRangeAt(0),o=n.cloneRange();return o.selectNodeContents(e),o.setEnd(n.startContainer,n.startOffset),t=o.toString().length,{start:t,end:t+n.toString().length}},e.restoreSelection=function(e,t){var n=document.createRange(),o=0;n.setStart(e,0),n.collapse(!0);for(var r,i,a=[e],s=!1,c=!1;!c&&(r=a.pop());)if(3==r.nodeType)i=o+r.length,!s&&t.start>=o&&t.start<=i&&(n.setStart(r,t.start-o),s=!0),s&&t.end>=o&&t.end<=i&&(n.setEnd(r,t.end-o),c=!0),o=i;else for(var l=r.childNodes.length;l--;)a.push(r.childNodes[l]);var d=window.getSelection();d.removeAllRanges(),d.addRange(n)},e.clearRange=function(){var e=window.getSelection();e.removeAllRanges()},e.hightlight=function(e){var n=e.dataset.type;document.queryCommandState(n)?t.toolbar.inline.setButtonHighlighted(e):t.toolbar.inline.removeButtonsHighLight(e);var o=window.getSelection(),r=o.anchorNode.parentNode;"A"==r.tagName&&"link"==n&&t.toolbar.inline.setButtonHighlighted(e)},e.setButtonHighlighted=function(e){if(e.classList.add("hightlighted"),"link"==e.dataset.type){var t=e.childNodes[0];t.classList.remove("ce-icon-link"),t.classList.add("ce-icon-unlink")}},e.removeButtonsHighLight=function(e){if(e.classList.remove("hightlighted"),"link"==e.dataset.type){var t=e.childNodes[0];t.classList.remove("ce-icon-unlink"),t.classList.add("ce-icon-link")}},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.opened=!1,e.open=function(){t.toolbar.settings.opened&&t.toolbar.settings.close(),t.nodes.toolbox.classList.add("opened"),t.nodes.plusButton.classList.add("clicked"),t.toolbar.toolbox.opened=!0},e.close=function(){t.nodes.toolbox.classList.remove("opened"),t.nodes.plusButton.classList.remove("clicked"),t.toolbar.toolbox.opened=!1},e.leaf=function(){var e=t.toolbar.current,n=Object.keys(t.tools),o=t.nodes.toolbarButtons,r=0,i=void 0,a=void 0,s=void 0;if(e)for(r=n.indexOf(e)+1,a=n[r];!t.tools[a].displayInToolbox;)r++,a=n[r],r==n.length&&(r=0,a=n[r]);else for(s in t.tools){if(t.tools[s].displayInToolbox)break;r++}i=n[r];for(var c in o)o[c].classList.remove("selected");o[i].classList.add("selected"),t.toolbar.current=i},e.toolClicked=function(e){var n,o,r,i=["image","link","list","instagram","twitter","embed"],a=t.tools[t.toolbar.current],s=t.content.currentNode,c=t.caret.inputIndex;n=a.render(),r={block:n,type:a.type,stretched:!1},s&&i.indexOf(s.dataset.tool)===-1&&""===s.textContent.trim()?t.content.switchBlock(s,n,a.type):(t.content.insertBlock(r),c++),o=a.appendCallback,o&&"function"==typeof o&&o.call(e),window.setTimeout(function(){t.caret.setToBlock(c)},10),t.content.workingNodeChanged(),t.toolbar.move()},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.globalKeydown=function(e){switch(e.keyCode){case t.core.keys.ENTER:t.callback.enterKeyPressed(e)}},e.redactorKeyDown=function(e){switch(e.keyCode){case t.core.keys.TAB:t.callback.tabKeyPressed(e);break;case t.core.keys.ENTER:t.callback.enterKeyPressedOnRedactorZone(e);break;case t.core.keys.ESC:t.callback.escapeKeyPressed(e);break;default:t.callback.defaultKeyPressed(e)}},e.globalKeyup=function(e){switch(e.keyCode){case t.core.keys.UP:case t.core.keys.LEFT:case t.core.keys.RIGHT:case t.core.keys.DOWN:t.callback.arrowKeyPressed(e)}},e.tabKeyPressed=function(e){var n=!t.content.currentNode.textContent.trim();n&&(t.toolbar.opened||t.toolbar.open(),t.toolbar.opened&&!t.toolbar.toolbox.opened?t.toolbar.toolbox.open():t.toolbar.toolbox.leaf(),e.preventDefault())},e.enterKeyPressed=function(){t.content.editorAreaHightlighted&&(t.caret.inputIndex=-1,t.callback.enterPressedOnBlock())},e.enterKeyPressedOnRedactorZone=function(e){"true"==e.target.contentEditable&&t.caret.saveCurrentInputIndex();var n=t.caret.getCurrentInputIndex()||0,o=t.content.currentNode,r=o.dataset.tool,i=t.toolbar.opened&&t.toolbar.current&&e.target==t.state.inputs[n],a=t.tools[r].enableLineBreaks,s=t.settings.initialBlockPlugin;if(i)return e.preventDefault(),t.toolbar.toolbox.toolClicked(e),t.toolbar.close(),e.stopPropagation(),void e.stopImmediatePropagation();if(e.shiftKey||a)return e.stopPropagation(),void e.stopImmediatePropagation();var c=window.getSelection(),l=c.anchorNode,d=t.caret.position.atTheEnd(),u=!1;if(e.shiftKey&&!a)return t.callback.enterPressedOnBlock(t.content.currentBlock,e),void e.preventDefault();if(u=l&&"true"!=l.parentNode.contentEditable,l.nodeType!=t.core.nodeTypes.TEXT||u||d){var p=t.content.isLastNode(l);p&&d&&(e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation(),t.core.log("ENTER clicked in last textNode. Create new BLOCK"),t.content.insertBlock({type:s,block:t.tools[s].render()},!0),t.toolbar.move(),t.toolbar.open(),t.toolbar.showPlusButton())}else e.preventDefault(),t.core.log("Splitting Text node..."),t.content.splitBlock(n),t.state.inputs[n+1].textContent.trim()||t.toolbar.showPlusButton();t.ui.saveInputs()},e.escapeKeyPressed=function(e){t.toolbar.close(),t.toolbar.toolbox.close(),e.preventDefault()},e.arrowKeyPressed=function(){t.content.workingNodeChanged(),t.toolbar.close(),t.toolbar.move()},e.defaultKeyPressed=function(){t.toolbar.close(),t.toolbar.inline.actionsOpened||(t.toolbar.inline.close(),t.content.clearMark())},e.redactorClicked=function(n){e.detectWhenClickedOnFirstLevelBlockArea(),t.content.workingNodeChanged(n.target),t.ui.saveInputs();var o,r=t.toolbar.inline.getSelectionText();if(0===r.length&&t.toolbar.inline.close(),"true"==n.target.contentEditable&&t.caret.saveCurrentInputIndex(),null===t.content.currentNode){var i=t.state.inputs.length>0?t.state.inputs.length-1:0;if(t.state.inputs.length&&(o=t.content.getFirstLevelBlock(t.state.inputs[i])),t.state.inputs.length&&""===t.state.inputs[i].textContent&&o.dataset.tool==t.settings.initialBlockPlugin)t.caret.setToBlock(i);else{var a=t.settings.initialBlockPlugin;t.content.insertBlock({type:a,block:t.tools[a].render() -}),1===t.state.inputs.length?t.caret.setToBlock(i):t.caret.setToNextBlock(i)}t.toolbar.move(),t.toolbar.open()}else t.toolbar.move(),t.toolbar.open(),t.toolbar.settings.close(),t.toolbar.toolbox.close();var s=!t.content.currentNode.textContent.trim(),c=t.content.currentNode.dataset.tool,l=c==t.settings.initialBlockPlugin;t.toolbar.hidePlusButton(),s||t.content.markBlock(),l&&s&&t.toolbar.showPlusButton()},e.detectWhenClickedOnFirstLevelBlockArea=function(){var e=window.getSelection(),n=e.anchorNode,o=!1;if(0===e.rangeCount)t.content.editorAreaHightlighted=!0;else{for(t.core.isDomNode(n)||(n=n.parentNode),"true"==n.contentEditable&&(o=!0);"true"!=n.contentEditable&&(n=n.parentNode,"true"==n.contentEditable&&(o=!0),n!=document.body););t.content.editorAreaHightlighted=!o}},e.toolbarButtonClicked=function(e){var n=this;t.toolbar.current=n.dataset.type,t.toolbar.toolbox.toolClicked(e),t.toolbar.close()},e.plusButtonClicked=function(){t.nodes.toolbox.classList.contains("opened")?t.toolbar.toolbox.close():t.toolbar.toolbox.open()},e.blockKeydown=function(e){var n=this;switch(e.keyCode){case t.core.keys.DOWN:case t.core.keys.RIGHT:t.callback.blockRightOrDownArrowPressed();break;case t.core.keys.BACKSPACE:t.callback.backspacePressed(n,e);break;case t.core.keys.UP:case t.core.keys.LEFT:t.callback.blockLeftOrUpArrowPressed()}},e.blockRightOrDownArrowPressed=function(){var e,n=window.getSelection(),o=t.state.inputs,r=n.anchorNode;if(!r)return!1;for(;"true"!=r.contentEditable;)e=r.parentNode,r=e;for(var i=0;r!=o[i];)i++;if(!r.textContent)return void t.caret.setToNextBlock(i);var a,s,c=!1,l=!1;return a=r.childNodes[r.childNodes.length-1],s=t.core.isDomNode(a)?t.content.getDeepestTextNodeFromPosition(a,a.childNodes.length):a,c=n.anchorNode==s,l=s.length==n.anchorOffset,c&&l?void t.caret.setToNextBlock(i):(t.core.log("arrow [down|right] : caret does not reached the end"),!1)},e.blockLeftOrUpArrowPressed=function(){var e,n=window.getSelection(),o=t.state.inputs,r=n.anchorNode;if(!r)return!1;if(0!==n.anchorOffset)return!1;for(;"true"!=r.contentEditable;)e=r.parentNode,r=e;for(var i=0;r!=o[i];)i++;var a,s,c=!1,l=!1;return r.textContent?(a=r.childNodes[0],s=t.core.isDomNode(a)?t.content.getDeepestTextNodeFromPosition(a,0):a,c=n.anchorNode==s,l=0===n.anchorOffset,void(c&&l&&t.caret.setToPreviousBlock(i))):void t.caret.setToPreviousBlock(i)},e.enterPressedOnBlock=function(){var e=t.settings.initialBlockPlugin;t.content.insertBlock({type:e,block:t.tools[e].render()},!0),t.toolbar.move(),t.toolbar.open()},e.backspacePressed=function(e,n){var o,r,i,a=t.caret.getCurrentInputIndex();if(e.textContent.trim()){if(o=t.content.getRange(),r=o.endOffset-o.startOffset,!t.caret.position.atStart()||r||!t.state.inputs[a-1])return;t.content.mergeBlocks(a)}r||e.remove(),i=t.nodes.redactor.childNodes.length,0===i?(t.content.currentNode=null,t.ui.addInitialBlock(),t.ui.saveInputs(),window.setTimeout(function(){t.caret.setToPreviousBlock(1)},10)):0!==t.caret.inputIndex?t.caret.setToPreviousBlock(t.caret.inputIndex):t.caret.setToNextBlock(t.caret.inputIndex),t.toolbar.move(),t.toolbar.opened||t.toolbar.open(),t.ui.saveInputs(),n.preventDefault()},e._blockPasteCallback=function(){var e=t.caret.getCurrentInputIndex(),n=new MutationObserver(t.callback.handleMutationsOnPaste),o={attributes:!0,childList:!1,characterData:!1,subtree:!0};n.observe(t.state.inputs[e],o)},e.blockPasteCallback=function(e){e.preventDefault();var n=t.content.getEditableParent(e.target),o=t.content.getFirstLevelBlock(e.target);if(n){var r,i,a=e.clipboardData.getData("text/html")||e.clipboardData.getData("text/plain"),s=t.draw.node("DIV","",{}),c=new t.sanitizer.init(t.sanitizer.Config.BASIC);i=document.createDocumentFragment(),r=c.clean(a),s.innerHTML=r;for(var l,d;l=s.firstChild;)d=i.appendChild(l);if(!t.tools[o.dataset.tool].allowRenderOnPaste||!t.paste.pasted(e)){var u,p;u=window.getSelection(),p=u.getRangeAt(0),p.deleteContents(),p.insertNode(i),d&&(p=p.cloneRange(),p.setStartAfter(d),p.collapse(!0),u.removeAllRanges(),u.addRange(p))}}},e.handleMutationsOnPaste=function(e){var n=this;e.forEach(function(e){t.content.paste.call(n,e)})},e.showSettingsButtonClicked=function(){var e=t.content.currentNode.dataset.tool;t.toolbar.settings.toggle(e),t.toolbar.toolbox.close(),t.toolbar.settings.hideRemoveActions()},e}({})},function(e,t){"use strict";e.exports=function(e){return e.wrapper=function(){var e=document.createElement("div");return e.className+="codex-editor",e},e.redactor=function(){var e=document.createElement("div");return e.className+="ce-redactor",e},e.ceBlock=function(){var e=document.createElement("DIV");return e.className+="ce_block",e},e.toolbar=function(){var e=document.createElement("div");return e.className+="ce-toolbar",e},e.toolbarContent=function(){var e=document.createElement("DIV");return e.classList.add("ce-toolbar__content"),e},e.inlineToolbar=function(){var e=document.createElement("DIV");return e.className+="ce-toolbar-inline",e},e.inlineToolbarButtons=function(){var e=document.createElement("DIV");return e.className+="ce-toolbar-inline__buttons",e},e.inlineToolbarActions=function(){var e=document.createElement("DIV");return e.className+="ce-toolbar-inline__actions",e},e.inputForLink=function(){var e=document.createElement("INPUT");return e.type="input",e.className+="inputForLink",e.placeholder="Вставьте ссылку ...",e.setAttribute("form","defaultForm"),e.setAttribute("autofocus","autofocus"),e},e.blockButtons=function(){var e=document.createElement("div");return e.className+="ce-toolbar__actions",e},e.blockSettings=function(){var e=document.createElement("div");return e.className+="ce-settings",e},e.defaultSettings=function(){var e=document.createElement("div");return e.classList.add("ce-settings_default"),e},e.pluginsSettings=function(){var e=document.createElement("div");return e.classList.add("ce-settings_plugin"),e},e.plusButton=function(){var e=document.createElement("span");return e.className="ce-toolbar__plus",e},e.settingsButton=function(){var e=document.createElement("span");return e.className="ce-toolbar__settings-btn",e.innerHTML='',e},e.toolbox=function(){var e=document.createElement("div");return e.className="ce-toolbar__tools",e},e.toolbarButton=function(e,t){var n=document.createElement("li"),o=document.createElement("i"),r=document.createElement("span");return n.dataset.type=e,n.setAttribute("title",e),o.classList.add(t),r.classList.add("ce_toolbar_tools--title"),n.appendChild(o),n.appendChild(r),n},e.toolbarButtonInline=function(e,t){var n=document.createElement("BUTTON"),o=document.createElement("I");return n.type="button",n.dataset.type=e,o.classList.add(t),n.appendChild(o),n},e.block=function(e,t){var n=document.createElement(e);return n.innerHTML=t||"",n},e.node=function(e,t,n){var o=document.createElement(e);if(t&&(o.className=t),n)for(var r in n)o[r]=n[r];return o},e.unavailableBlock=function(){var e=document.createElement("DIV");return e.classList.add("cdx-unavailable-block"),e},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.inputIndex=null,e.offset=null,e.focusedNodeIndex=null,e.set=function(n,o,r){r=r||e.offset||0,o=o||e.focusedNodeIndex||0;var i,a=n.childNodes;if(i=0===a.length?n:a[o],"INPUT"==n.tagName)return void n.focus();t.core.isDomNode(i)&&(i=t.content.getDeepestTextNodeFromPosition(i,i.childNodes.length));var s=document.createRange(),c=window.getSelection();window.setTimeout(function(){s.setStart(i,r),s.setEnd(i,r),c.removeAllRanges(),c.addRange(s),t.caret.saveCurrentInputIndex()},20)},e.saveCurrentInputIndex=function(){var n,o=window.getSelection(),r=t.state.inputs,i=o.anchorNode;if(i){for(;"true"!=i.contentEditable;)n=i.parentNode,i=n;for(var a=0;i!=r[a];)a++;e.inputIndex=a}},e.getCurrentInputIndex=function(){return e.inputIndex},e.setToNextBlock=function(e){var n=t.state.inputs,o=n[e+1];if(!o)return void t.core.log("We are reached the end");if(!o.childNodes.length){var r=document.createTextNode("");o.appendChild(r)}t.caret.inputIndex=e+1,t.caret.set(o,0,0),t.content.workingNodeChanged(o)},e.setToBlock=function(e){var n=t.state.inputs,o=n[e];if(o){if(!o.childNodes.length){var r=document.createTextNode("");o.appendChild(r)}t.caret.inputIndex=e,t.caret.set(o,0,0),t.content.workingNodeChanged(o)}},e.setToPreviousBlock=function(e){e=e||0;var n,o,r,i=t.state.inputs,a=i[e-1];return a?(n=t.content.getDeepestTextNodeFromPosition(a,a.childNodes.length),o=n.length,a.childNodes.length||(r=document.createTextNode(""),a.appendChild(r)),t.caret.inputIndex=e-1,t.caret.set(a,a.childNodes.length-1,o),void t.content.workingNodeChanged(i[e-1])):void t.core.log("We are reached first node")},e.position={atStart:function(){var e=window.getSelection(),n=e.anchorOffset,o=e.anchorNode,r=t.content.getFirstLevelBlock(o),i=r.childNodes[0];t.core.isDomNode(o)||(o=o.parentNode);var a=o===i.childNodes[0],s=0===n;return a&&s},atTheEnd:function(){var e=window.getSelection(),t=e.anchorOffset,n=e.anchorNode;return!n||!n.length||t===n.length}},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor,n=[],o=function(e){n.push(e);for(var t=0;t5;)"confirm"!=n[t].type&&"prompt"!=n[t].type?(n[t].close(),n.splice(t,1)):t++};return e.createHolder=function(){var e=t.draw.node("DIV","cdx-notifications-block");return t.nodes.notifications=document.body.appendChild(e),e},e.errorThrown=function(e,n){t.notifications.notification({message:"This action is not available currently",type:n.type})},e.notification=function(e){function n(e){if(!e||!e.message)return void t.core.log("Can't create notification. Message is missed");e.type=e.type||"alert",e.time=1e3*e.time||1e4;var n=t.draw.node("DIV","cdx-notification"),o=t.draw.node("DIV","cdx-notification__message"),r=t.draw.node("INPUT","cdx-notification__input"),f=t.draw.node("SPAN","cdx-notification__ok-btn"),h=t.draw.node("SPAN","cdx-notification__cancel-btn");o.textContent=e.message,f.textContent=e.okMsg||"ОК",h.textContent=e.cancelMsg||"Отмена",t.listeners.add(f,"click",u),t.listeners.add(h,"click",p),n.appendChild(o),"prompt"==e.type&&n.appendChild(r),n.appendChild(f),"prompt"!=e.type&&"confirm"!=e.type||n.appendChild(h),n.classList.add("cdx-notification-"+e.type),n.dataset.type=e.type,a=n,c=e.type,l=e.confirm,s=e.cancel,d=r,"prompt"!=e.type&&"confirm"!=e.type&&window.setTimeout(i,e.time)}function r(){t.nodes.notifications.appendChild(a),d.focus(),t.nodes.notifications.classList.add("cdx-notification__notification-appending"),window.setTimeout(function(){t.nodes.notifications.classList.remove("cdx-notification__notification-appending")},100),o({type:c,close:i})}function i(){a.remove()}var a=null,s=null,c=null,l=null,d=null,u=function(){if(i(),"function"==typeof l)return"prompt"==c?void l(d.value):void l()},p=function(){i(),"function"==typeof s&&s()};return e&&(n(e),r()),{create:n,send:r,close:i}},e.clear=function(){t.nodes.notifications.innerHTML="",n=[]},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.insertPastedContent=function(e,n){t.content.insertBlock({type:e.type,block:e.render({text:n.innerHTML})})},e.isFirstLevelBlock=function(e){return e.nodeType==t.core.nodeTypes.TAG&&e.classList.contains(t.ui.className.BLOCK_CLASSNAME)},e}({})},function(e,t,n){"use strict";e.exports=function(e){var t=n(18),o={BASIC:{tags:{p:{},a:{href:!0,target:"_blank",rel:"nofollow"},i:{},b:{},strong:{},em:{},span:{}}}};return e.Config=o,e.init=t,e}({})},function(e,t,n){var o,r;!function(i,a){o=a,r="function"==typeof o?o.call(t,n,t,e):o,!(void 0!==r&&(e.exports=r))}(this,function(){function e(e){var t=e.tags,n=Object.keys(t),o=n.map(function(e){return typeof t[e]}).every(function(e){return"object"===e||"boolean"===e||"function"===e});if(!o)throw new Error("The configuration was invalid");this.config=e}function t(e){return s.indexOf(e.nodeName)!==-1}function n(e){return c.indexOf(e.nodeName)!==-1}function o(e){return document.createTreeWalker(e,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT,null,!1)}function r(e,t,n){return"function"==typeof e.tags[t]?e.tags[t](n):e.tags[t]}function i(e,t){return"undefined"==typeof t||"boolean"==typeof t&&!t}function a(e,t,n){var o=e.name.toLowerCase();return t!==!0&&("function"==typeof t[o]?!t[o](e.value,n):"undefined"==typeof t[o]||(t[o]===!1||"string"==typeof t[o]&&t[o]!==e.value))}var s=["P","LI","TD","TH","DIV","H1","H2","H3","H4","H5","H6","PRE"],c=["A","B","STRONG","I","EM","SUB","SUP","U","STRIKE"];return e.prototype.clean=function(e){var t=document.createElement("div");return t.innerHTML=e,this._sanitize(t),t.innerHTML},e.prototype._sanitize=function(e){var s=o(e),c=s.firstChild();if(c)do if(!c._sanitized)if(c.nodeType!==Node.TEXT_NODE){if(c.nodeType===Node.COMMENT_NODE){e.removeChild(c),this._sanitize(e);break}var l,d=n(c);d&&(l=Array.prototype.some.call(c.childNodes,t));var u=!!e.parentNode,p=t(e)&&t(c)&&u,f=c.nodeName.toLowerCase(),h=r(this.config,f,c),g=d&&l;if(g||i(c,h)||!this.config.keepNestedBlockElements&&p){if("SCRIPT"!==c.nodeName&&"STYLE"!==c.nodeName)for(;c.childNodes.length>0;)e.insertBefore(c.childNodes[0],c);e.removeChild(c),this._sanitize(e);break}for(var b=0;b=t.core.keys.LEFT&&e.keyCode<=t.core.keys.DOWN&&e.stopPropagation()},e.rusToTranslit=function(e){for(var t=["А","Б","В","Г","Д","Е","Ё","Ж","З","И","Й","К","Л","М","Н","О","П","Р","С","Т","У","Ф","Х","Ц","Ч","Ш","Щ","Ь","Ы","Ь","Э","Ю","Я"],n=["A","B","V","G","D","E","E","Zh","Z","I","Y","K","L","M","N","O","P","R","S","T","U","F","H","C","Ch","Sh","Sch","","Y","","E","Yu","Ya"],o=0;o0&&t.splice(s,1)}},e.removeAll=function(){t.map(function(t){e.remove(t.element,t.type,t.handler)})},e.get=function(t,n,o){return e.search.all(t,n,o)},e}({})},function(e,t){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};e.exports=function(e){var t=codex.editor;return e.removeNodes=function(){t.nodes.wrapper.remove(),t.nodes.notifications.remove()},e.destroyPlugins=function(){for(var e in t.tools)"function"==typeof t.tools[e].destroy&&t.tools[e].destroy()},e.destroyScripts=function(){for(var e=document.getElementsByTagName("SCRIPT"),n=0;nНе выводить в ленте'}:{innerHTML:'Вывести в ленте'},e=t.draw.node("DIV",t.ui.className.SETTINGS_ITEM,n),t.listeners.add(e,"click",t.toolbar.settings.updateFeedMode,!1),e},e.updateFeedMode=function(){var e=t.content.currentNode;e.classList.toggle(t.ui.className.BLOCK_IN_FEED_MODE),t.toolbar.settings.close()},e.isFeedModeActivated=function(){var e=t.content.currentNode;return!!e&&e.classList.contains(t.ui.className.BLOCK_IN_FEED_MODE)},e.makeAnchorInput=function(){var e=t.draw.node("div","ce-settings__anchor-wrapper ce-settings__item",{}),n=t.draw.node("i","ce-settings__anchor-hash",{}),o=t.draw.node("input","ce-settings__anchor-input",{placeholder:"Якорь"});return t.listeners.add(o,"keydown",t.anchors.keyDownOnAnchorInput),t.listeners.add(o,"keyup",t.anchors.keyUpOnAnchorInput),t.listeners.add(o,"input",t.anchors.anchorChanged),t.listeners.add(o,"blur",t.anchors.anchorChanged),e.appendChild(n),e.appendChild(o),t.anchors.input=o,e},e.makeRemoveBlockButton=function(){var e=t.draw.node("SPAN","ce-toolbar__remove-btn",{}),n=t.draw.node("SPAN","ce-toolbar__remove-setting",{innerHTML:''}),o=t.draw.node("DIV","ce-toolbar__remove-confirmation",{}),r=t.draw.node("DIV","ce-toolbar__remove-confirm",{textContent:"Удалить блок"}),i=t.draw.node("DIV","ce-toolbar__remove-cancel",{textContent:"Отмена"});return t.listeners.add(n,"click",t.toolbar.settings.removeButtonClicked,!1),t.listeners.add(r,"click",t.toolbar.settings.confirmRemovingRequest,!1),t.listeners.add(i,"click",t.toolbar.settings.cancelRemovingRequest,!1),o.appendChild(r),o.appendChild(i),e.appendChild(n),e.appendChild(o),t.toolbar.settings.setting=n,t.toolbar.settings.actions=o,e},e.removeButtonClicked=function(){var e=t.toolbar.settings.actions;e.classList.contains("opened")?t.toolbar.settings.hideRemoveActions():t.toolbar.settings.showRemoveActions(),t.toolbar.toolbox.close(),t.toolbar.settings.close()},e.cancelRemovingRequest=function(){t.toolbar.settings.actions.classList.remove("opened")},e.confirmRemovingRequest=function(){var e,n=t.content.currentNode;n.remove(),e=t.nodes.redactor.childNodes.length,0===e&&(t.content.currentNode=null,t.ui.addInitialBlock()),t.ui.saveInputs(),t.toolbar.close()},e.showRemoveActions=function(){t.toolbar.settings.actions.classList.add("opened")},e.hideRemoveActions=function(){t.toolbar.settings.actions.classList.remove("opened")},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;e.buttonsOpened=null,e.actionsOpened=null,e.wrappersOffset=null,e.storedSelection=null,e.show=function(){var n,o=t.content.currentNode,r=o.dataset.tool;if(n=t.tools[r],n.showInlineToolbar){var i=e.getSelectionText(),a=t.nodes.inlineToolbar.wrapper;i.length>0&&(t.toolbar.inline.move(),a.classList.add("opened"),t.toolbar.inline.showButtons())}},e.close=function(){var e=t.nodes.inlineToolbar.wrapper;e.classList.remove("opened")},e.move=function(){this.wrappersOffset||(this.wrappersOffset=this.getWrappersOffset());var e,n,o=this.getSelectionCoords(),r=0,i=t.nodes.inlineToolbar.wrapper;0===i.offsetHeight&&(r=40),e=o.x-this.wrappersOffset.left,n=o.y+window.scrollY-this.wrappersOffset.top-r-i.offsetHeight,i.style.transform="translate3D("+Math.floor(e)+"px, "+Math.floor(n)+"px, 0)",t.toolbar.inline.closeButtons(),t.toolbar.inline.closeAction()},e.toolClicked=function(e,n){switch(n){case"createLink":t.toolbar.inline.createLinkAction(e,n);break;default:t.toolbar.inline.defaultToolAction(n)}t.nodes.inlineToolbar.buttons.childNodes.forEach(t.toolbar.inline.hightlight)},e.getWrappersOffset=function(){var e=t.nodes.wrapper,n=this.getOffset(e);return this.wrappersOffset=n,n},e.getOffset=function(e){for(var t=0,n=0;e&&!isNaN(e.offsetLeft)&&!isNaN(e.offsetTop);)t+=e.offsetLeft+e.clientLeft,n+=e.offsetTop+e.clientTop,e=e.offsetParent;return{top:n,left:t}},e.getSelectionCoords=function(){var e,t=document.selection,n=0,o=0;if(t)"Control"!=t.type&&(e=t.createRange(),e.collapse(!0),n=e.boundingLeft,o=e.boundingTop);else if(window.getSelection&&(t=window.getSelection(),t.rangeCount&&(e=t.getRangeAt(0).cloneRange(),e.getClientRects))){e.collapse(!0);var r=e.getClientRects()[0];if(!r)return;n=r.left,o=r.top}return{x:n,y:o}},e.getSelectionText=function(){var e="";return window.getSelection&&(e=window.getSelection().toString()),e},e.showButtons=function(){var e=t.nodes.inlineToolbar.buttons;e.classList.add("opened"),t.toolbar.inline.buttonsOpened=!0,t.nodes.inlineToolbar.buttons.childNodes.forEach(t.toolbar.inline.hightlight)},e.closeButtons=function(){var e=t.nodes.inlineToolbar.buttons;e.classList.remove("opened"),t.toolbar.inline.buttonsOpened=!1},e.showActions=function(){var e=t.nodes.inlineToolbar.actions;e.classList.add("opened"),t.toolbar.inline.actionsOpened=!0},e.closeAction=function(){var e=t.nodes.inlineToolbar.actions;e.innerHTML="",e.classList.remove("opened"),t.toolbar.inline.actionsOpened=!1};var n=function(e){if(e.keyCode==t.core.keys.ENTER){var n=t.content.currentNode,o=t.toolbar.inline.storedSelection;t.toolbar.inline.restoreSelection(n,o),t.toolbar.inline.setAnchor(this.value),e.preventDefault(),e.stopImmediatePropagation(),t.toolbar.inline.clearRange()}};return e.createLinkAction=function(e){var o=this.isLinkActive(),r=t.content.currentNode,i=t.toolbar.inline.saveSelection(r);if(t.toolbar.inline.storedSelection=i,o)t.toolbar.inline.restoreSelection(r,i),t.toolbar.inline.defaultToolAction("unlink");else{var a=t.draw.inputForLink();t.nodes.inlineToolbar.actions.appendChild(a),t.toolbar.inline.closeButtons(),t.toolbar.inline.showActions(),a.focus(),e.preventDefault(),t.listeners.add(a,"keydown",n,!1)}},e.isLinkActive=function(){var e=!1;return t.nodes.inlineToolbar.buttons.childNodes.forEach(function(t){var n=t.dataset.type;"link"==n&&t.classList.contains("hightlighted")&&(e=!0)}),e},e.defaultToolAction=function(e){document.execCommand(e,!1,null)},e.setAnchor=function(e){document.execCommand("createLink",!1,e),t.toolbar.inline.closeAction()},e.saveSelection=function(e){var t,n=window.getSelection().getRangeAt(0),o=n.cloneRange();return o.selectNodeContents(e),o.setEnd(n.startContainer,n.startOffset),t=o.toString().length,{start:t,end:t+n.toString().length}},e.restoreSelection=function(e,t){var n=document.createRange(),o=0;n.setStart(e,0),n.collapse(!0);for(var r,i,a=[e],s=!1,c=!1;!c&&(r=a.pop());)if(3==r.nodeType)i=o+r.length,!s&&t.start>=o&&t.start<=i&&(n.setStart(r,t.start-o),s=!0),s&&t.end>=o&&t.end<=i&&(n.setEnd(r,t.end-o),c=!0),o=i;else for(var l=r.childNodes.length;l--;)a.push(r.childNodes[l]);var d=window.getSelection();d.removeAllRanges(),d.addRange(n)},e.clearRange=function(){var e=window.getSelection();e.removeAllRanges()},e.hightlight=function(e){var n=e.dataset.type;document.queryCommandState(n)?t.toolbar.inline.setButtonHighlighted(e):t.toolbar.inline.removeButtonsHighLight(e);var o=window.getSelection(),r=o.anchorNode.parentNode;"A"==r.tagName&&"link"==n&&t.toolbar.inline.setButtonHighlighted(e)},e.setButtonHighlighted=function(e){if(e.classList.add("hightlighted"),"link"==e.dataset.type){var t=e.childNodes[0];t.classList.remove("ce-icon-link"),t.classList.add("ce-icon-unlink")}},e.removeButtonsHighLight=function(e){if(e.classList.remove("hightlighted"),"link"==e.dataset.type){var t=e.childNodes[0];t.classList.remove("ce-icon-unlink"),t.classList.add("ce-icon-link")}},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.opened=!1,e.open=function(){t.toolbar.settings.opened&&t.toolbar.settings.close(),t.nodes.toolbox.classList.add("opened"),t.nodes.plusButton.classList.add("clicked"),t.toolbar.toolbox.opened=!0},e.close=function(){t.nodes.toolbox.classList.remove("opened"),t.nodes.plusButton.classList.remove("clicked"),t.toolbar.toolbox.opened=!1,t.toolbar.current=null},e.leaf=function(){var e=t.toolbar.current,n=Object.keys(t.tools),o=t.nodes.toolbarButtons,r=0,i=void 0,a=void 0,s=void 0;if(e)for(r=(n.indexOf(e)+1)%n.length,a=n[r];!t.tools[a].displayInToolbox;)r=(r+1)%n.length,a=n[r];else for(s in t.tools){if(t.tools[s].displayInToolbox)break;r++}i=n[r];for(var c in o)o[c].classList.remove("selected");o[i].classList.add("selected"),t.toolbar.current=i},e.toolClicked=function(e){var n,o,r,i=["image","link","list","instagram","twitter","embed"],a=t.tools[t.toolbar.current],s=t.content.currentNode,c=t.caret.inputIndex;n=a.render(),r={block:n,type:a.type,stretched:!1},s&&i.indexOf(s.dataset.tool)===-1&&""===s.textContent.trim()?t.content.switchBlock(s,n,a.type):(t.content.insertBlock(r),c++),o=a.appendCallback,o&&"function"==typeof o&&o.call(e),window.setTimeout(function(){t.caret.setToBlock(c)},10),t.content.workingNodeChanged(),t.toolbar.move()},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;e.globalKeydown=function(e){switch(e.keyCode){case t.core.keys.ENTER:t.callback.enterKeyPressed(e)}},e.redactorKeyDown=function(e){switch(e.keyCode){case t.core.keys.TAB:t.callback.tabKeyPressed(e);break;case t.core.keys.ENTER:t.callback.enterKeyPressedOnRedactorZone(e);break;case t.core.keys.ESC:t.callback.escapeKeyPressed(e);break;default:t.callback.defaultKeyPressed(e)}},e.globalKeyup=function(e){switch(e.keyCode){case t.core.keys.UP:case t.core.keys.LEFT:case t.core.keys.RIGHT:case t.core.keys.DOWN:t.callback.arrowKeyPressed(e)}},e.tabKeyPressed=function(e){var n=t.content.currentNode.querySelectorAll("textarea, input"),o=!0,r=!t.content.currentNode.textContent.trim();Array.prototype.map.call(n,function(e){"textarea"!=e.type&&"text"!=e.type||(o=o&&!e.value.trim())});var i=r&&o;i&&(t.toolbar.opened||t.toolbar.open(),t.toolbar.opened&&!t.toolbar.toolbox.opened?t.toolbar.toolbox.open():t.toolbar.toolbox.leaf(),e.preventDefault())},e.enterKeyPressed=function(){t.content.editorAreaHightlighted&&(t.caret.inputIndex=-1,t.callback.enterPressedOnBlock())},e.enterKeyPressedOnRedactorZone=function(e){"true"==e.target.contentEditable&&t.caret.saveCurrentInputIndex();var n=t.caret.getCurrentInputIndex()||0,o=t.content.currentNode,r=o.dataset.tool,i=t.toolbar.opened&&t.toolbar.current&&e.target==t.state.inputs[n],a=t.tools[r].enableLineBreaks,s=t.settings.initialBlockPlugin;if(i)return e.preventDefault(),t.toolbar.toolbox.toolClicked(e),t.toolbar.close(),e.stopPropagation(),void e.stopImmediatePropagation();if(e.shiftKey||a)return e.stopPropagation(),void e.stopImmediatePropagation();var c=window.getSelection(),l=c.anchorNode,d=t.caret.position.atTheEnd(),u=!1;if(e.shiftKey&&!a)return t.callback.enterPressedOnBlock(t.content.currentBlock,e),void e.preventDefault();if(u=l&&"true"!=l.parentNode.contentEditable,l.nodeType!=t.core.nodeTypes.TEXT||u||d){var p=t.content.isLastNode(l);p&&d&&(e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation(),t.core.log("ENTER clicked in last textNode. Create new BLOCK"),t.content.insertBlock({type:s,block:t.tools[s].render()},!0),t.toolbar.move(),t.toolbar.open(),t.toolbar.showPlusButton())}else e.preventDefault(),t.core.log("Splitting Text node..."),t.content.splitBlock(n),t.state.inputs[n+1].textContent.trim()||t.toolbar.showPlusButton();t.ui.saveInputs()},e.escapeKeyPressed=function(e){t.toolbar.close(),t.toolbar.toolbox.close(),e.preventDefault()},e.arrowKeyPressed=function(){t.content.workingNodeChanged(),t.toolbar.close(),t.toolbar.move()},e.defaultKeyPressed=function(){t.toolbar.close(),t.toolbar.inline.actionsOpened||(t.toolbar.inline.close(),t.content.clearMark())},e.redactorClicked=function(n){e.detectWhenClickedOnFirstLevelBlockArea(),t.content.workingNodeChanged(n.target),t.ui.saveInputs();var o,r=t.toolbar.inline.getSelectionText();if(0===r.length&&t.toolbar.inline.close(),"true"==n.target.contentEditable&&t.caret.saveCurrentInputIndex(),null===t.content.currentNode){var i=t.state.inputs.length>0?t.state.inputs.length-1:0; +if(t.state.inputs.length&&(o=t.content.getFirstLevelBlock(t.state.inputs[i])),t.state.inputs.length&&""===t.state.inputs[i].textContent&&o.dataset.tool==t.settings.initialBlockPlugin)t.caret.setToBlock(i);else{var a=t.settings.initialBlockPlugin;t.content.insertBlock({type:a,block:t.tools[a].render()}),1===t.state.inputs.length?t.caret.setToBlock(i):t.caret.setToNextBlock(i)}t.toolbar.move(),t.toolbar.open()}else t.toolbar.move(),t.toolbar.open(),t.toolbar.settings.close(),t.toolbar.toolbox.close();var s=!t.content.currentNode.textContent.trim(),c=t.content.currentNode.dataset.tool,l=c==t.settings.initialBlockPlugin;t.toolbar.hidePlusButton(),s||t.content.markBlock(),l&&s&&t.toolbar.showPlusButton()},e.detectWhenClickedOnFirstLevelBlockArea=function(){var e=window.getSelection(),n=e.anchorNode,o=!1;if(0===e.rangeCount)t.content.editorAreaHightlighted=!0;else{for(t.core.isDomNode(n)||(n=n.parentNode),"true"==n.contentEditable&&(o=!0);"true"!=n.contentEditable&&(n=n.parentNode,"true"==n.contentEditable&&(o=!0),n!=document.body););t.content.editorAreaHightlighted=!o}},e.toolbarButtonClicked=function(e){var n=this;t.toolbar.current=n.dataset.type,t.toolbar.toolbox.toolClicked(e),t.toolbar.close()},e.plusButtonClicked=function(){t.nodes.toolbox.classList.contains("opened")?t.toolbar.toolbox.close():t.toolbar.toolbox.open()},e.blockKeydown=function(e){var n=this;switch(e.keyCode){case t.core.keys.DOWN:case t.core.keys.RIGHT:t.callback.blockRightOrDownArrowPressed();break;case t.core.keys.BACKSPACE:t.callback.backspacePressed(n,e);break;case t.core.keys.UP:case t.core.keys.LEFT:t.callback.blockLeftOrUpArrowPressed()}},e.blockRightOrDownArrowPressed=function(){var e,n=window.getSelection(),o=t.state.inputs,r=n.anchorNode;if(!r)return!1;for(;"true"!=r.contentEditable;)e=r.parentNode,r=e;for(var i=0;r!=o[i];)i++;if(!r.textContent)return void t.caret.setToNextBlock(i);var a,s,c=!1,l=!1;return a=r.childNodes[r.childNodes.length-1],s=t.core.isDomNode(a)?t.content.getDeepestTextNodeFromPosition(a,a.childNodes.length):a,c=n.anchorNode==s,l=s.length==n.anchorOffset,c&&l?void t.caret.setToNextBlock(i):(t.core.log("arrow [down|right] : caret does not reached the end"),!1)},e.blockLeftOrUpArrowPressed=function(){var e,n=window.getSelection(),o=t.state.inputs,r=n.anchorNode;if(!r)return!1;if(0!==n.anchorOffset)return!1;for(;"true"!=r.contentEditable;)e=r.parentNode,r=e;for(var i=0;r!=o[i];)i++;var a,s,c=!1,l=!1;return r.textContent?(a=r.childNodes[0],s=t.core.isDomNode(a)?t.content.getDeepestTextNodeFromPosition(a,0):a,c=n.anchorNode==s,l=0===n.anchorOffset,void(c&&l&&t.caret.setToPreviousBlock(i))):void t.caret.setToPreviousBlock(i)},e.enterPressedOnBlock=function(){var e=t.settings.initialBlockPlugin;t.content.insertBlock({type:e,block:t.tools[e].render()},!0),t.toolbar.move(),t.toolbar.open()},e.backspacePressed=function(e,o){var r,i,a,s=t.caret.getCurrentInputIndex();if(n(o.target)){if(""!=o.target.value.trim())return;e.remove()}if(e.textContent.trim()){if(r=t.content.getRange(),i=r.endOffset-r.startOffset,!t.caret.position.atStart()||i||!t.state.inputs[s-1])return;t.content.mergeBlocks(s)}i||e.remove(),a=t.nodes.redactor.childNodes.length,0===a?(t.content.currentNode=null,t.ui.addInitialBlock(),t.ui.saveInputs(),window.setTimeout(function(){t.caret.setToPreviousBlock(1)},10)):0!==t.caret.inputIndex?t.caret.setToPreviousBlock(t.caret.inputIndex):t.caret.setToNextBlock(t.caret.inputIndex),t.toolbar.move(),t.toolbar.opened||t.toolbar.open(),t.ui.saveInputs(),o.preventDefault()},e._blockPasteCallback=function(){var e=t.caret.getCurrentInputIndex(),n=new MutationObserver(t.callback.handleMutationsOnPaste),o={attributes:!0,childList:!1,characterData:!1,subtree:!0};n.observe(t.state.inputs[e],o)},e.blockPasteCallback=function(e){if(!n(e.target)){e.preventDefault();var o=t.content.getEditableParent(e.target),r=t.content.currentNode;if(o){var i,a,s=e.clipboardData.getData("text/html"),c=e.clipboardData.getData("text/plain"),l=t.draw.node("DIV","",{}),d=new t.sanitizer.init(t.sanitizer.Config.BASIC);a=document.createDocumentFragment(),""!=s.trim()?(i=d.clean(s),l.innerHTML=i):l.innerText=c.toString();for(var u,p;u=l.firstChild;)p=a.appendChild(u);if(!t.tools[r.dataset.tool].allowRenderOnPaste||!t.paste.pasted(e)){var f,h;f=window.getSelection(),h=f.getRangeAt(0),h.deleteContents(),h.insertNode(a),p&&(h=h.cloneRange(),h.setStartAfter(p),h.collapse(!0),f.removeAllRanges(),f.addRange(h))}}}},e.handleMutationsOnPaste=function(e){var n=this;e.forEach(function(e){t.content.paste.call(n,e)})},e.showSettingsButtonClicked=function(){var e=t.content.currentNode.dataset.tool;t.toolbar.settings.toggle(e),t.toolbar.toolbox.close(),t.toolbar.settings.hideRemoveActions()};var n=function(e){var t=["INPUT","TEXTAREA"];return t.indexOf(e.tagName)!=-1};return e}({})},function(e,t){"use strict";e.exports=function(e){return e.wrapper=function(){var e=document.createElement("div");return e.className+="codex-editor",e},e.redactor=function(){var e=document.createElement("div");return e.className+="ce-redactor",e},e.ceBlock=function(){var e=document.createElement("DIV");return e.className+="ce_block",e},e.toolbar=function(){var e=document.createElement("div");return e.className+="ce-toolbar",e},e.toolbarContent=function(){var e=document.createElement("DIV");return e.classList.add("ce-toolbar__content"),e},e.inlineToolbar=function(){var e=document.createElement("DIV");return e.className+="ce-toolbar-inline",e},e.inlineToolbarButtons=function(){var e=document.createElement("DIV");return e.className+="ce-toolbar-inline__buttons",e},e.inlineToolbarActions=function(){var e=document.createElement("DIV");return e.className+="ce-toolbar-inline__actions",e},e.inputForLink=function(){var e=document.createElement("INPUT");return e.type="input",e.className+="inputForLink",e.placeholder="Вставьте ссылку ...",e.setAttribute("form","defaultForm"),e.setAttribute("autofocus","autofocus"),e},e.blockButtons=function(){var e=document.createElement("div");return e.className+="ce-toolbar__actions",e},e.blockSettings=function(){var e=document.createElement("div");return e.className+="ce-settings",e},e.defaultSettings=function(){var e=document.createElement("div");return e.classList.add("ce-settings_default"),e},e.pluginsSettings=function(){var e=document.createElement("div");return e.classList.add("ce-settings_plugin"),e},e.plusButton=function(){var e=document.createElement("span");return e.className="ce-toolbar__plus",e},e.settingsButton=function(){var e=document.createElement("span");return e.className="ce-toolbar__settings-btn",e.innerHTML='',e},e.toolbox=function(){var e=document.createElement("div");return e.className="ce-toolbar__tools",e},e.toolbarButton=function(e,t){var n=document.createElement("li"),o=document.createElement("i"),r=document.createElement("span");return n.dataset.type=e,n.setAttribute("title",e),o.classList.add(t),r.classList.add("ce_toolbar_tools--title"),n.appendChild(o),n.appendChild(r),n},e.toolbarButtonInline=function(e,t){var n=document.createElement("BUTTON"),o=document.createElement("I");return n.type="button",n.dataset.type=e,o.classList.add(t),n.appendChild(o),n},e.block=function(e,t){var n=document.createElement(e);return n.innerHTML=t||"",n},e.node=function(e,t,n){var o=document.createElement(e);if(t&&(o.className=t),n)for(var r in n)o[r]=n[r];return o},e.unavailableBlock=function(){var e=document.createElement("DIV");return e.classList.add("cdx-unavailable-block"),e},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.inputIndex=null,e.offset=null,e.focusedNodeIndex=null,e.set=function(n,o,r){r=r||e.offset||0,o=o||e.focusedNodeIndex||0;var i,a=n.childNodes;if(i=0===a.length?n:a[o],"true"!=n.contentEditable)return void n.focus();t.core.isDomNode(i)&&(i=t.content.getDeepestTextNodeFromPosition(i,i.childNodes.length));var s=document.createRange(),c=window.getSelection();window.setTimeout(function(){s.setStart(i,r),s.setEnd(i,r),c.removeAllRanges(),c.addRange(s),t.caret.saveCurrentInputIndex()},20)},e.saveCurrentInputIndex=function(){var n,o=window.getSelection(),r=t.state.inputs,i=o.anchorNode;if(i){for(;"true"!=i.contentEditable;)n=i.parentNode,i=n;for(var a=0;i!=r[a];)a++;e.inputIndex=a}},e.getCurrentInputIndex=function(){return e.inputIndex},e.setToNextBlock=function(e){var n=t.state.inputs,o=n[e+1];if(!o)return void t.core.log("We are reached the end");if(!o.childNodes.length){var r=document.createTextNode("");o.appendChild(r)}t.caret.inputIndex=e+1,t.caret.set(o,0,0),t.content.workingNodeChanged(o)},e.setToBlock=function(e){var n=t.state.inputs,o=n[e];if(o){if(!o.childNodes.length){var r=document.createTextNode("");o.appendChild(r)}t.caret.inputIndex=e,t.caret.set(o,0,0),t.content.workingNodeChanged(o)}},e.setToPreviousBlock=function(e){e=e||0;var n,o,r,i=t.state.inputs,a=i[e-1];return a?(n=t.content.getDeepestTextNodeFromPosition(a,a.childNodes.length),o=n.length,a.childNodes.length||(r=document.createTextNode(""),a.appendChild(r)),t.caret.inputIndex=e-1,t.caret.set(a,a.childNodes.length-1,o),void t.content.workingNodeChanged(i[e-1])):void t.core.log("We are reached first node")},e.position={atStart:function(){var e=window.getSelection(),n=e.anchorOffset,o=e.anchorNode,r=t.content.getFirstLevelBlock(o),i=r.childNodes[0];t.core.isDomNode(o)||(o=o.parentNode);var a=o===i.childNodes[0],s=0===n;return a&&s},atTheEnd:function(){var e=window.getSelection(),t=e.anchorOffset,n=e.anchorNode;return!n||!n.length||t===n.length}},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor,n=[],o=function(e){n.push(e);for(var t=0;t5;)"confirm"!=n[t].type&&"prompt"!=n[t].type?(n[t].close(),n.splice(t,1)):t++};return e.createHolder=function(){var e=t.draw.node("DIV","cdx-notifications-block");return t.nodes.notifications=document.body.appendChild(e),e},e.errorThrown=function(e,n){t.notifications.notification({message:"This action is not available currently",type:n.type})},e.notification=function(e){function n(e){if(!e||!e.message)return void t.core.log("Can't create notification. Message is missed");e.type=e.type||"alert",e.time=1e3*e.time||1e4;var n=t.draw.node("DIV","cdx-notification"),o=t.draw.node("DIV","cdx-notification__message"),r=t.draw.node("INPUT","cdx-notification__input"),f=t.draw.node("SPAN","cdx-notification__ok-btn"),h=t.draw.node("SPAN","cdx-notification__cancel-btn");o.textContent=e.message,f.textContent=e.okMsg||"ОК",h.textContent=e.cancelMsg||"Отмена",t.listeners.add(f,"click",u),t.listeners.add(h,"click",p),n.appendChild(o),"prompt"==e.type&&n.appendChild(r),n.appendChild(f),"prompt"!=e.type&&"confirm"!=e.type||n.appendChild(h),n.classList.add("cdx-notification-"+e.type),n.dataset.type=e.type,a=n,c=e.type,l=e.confirm,s=e.cancel,d=r,"prompt"!=e.type&&"confirm"!=e.type&&window.setTimeout(i,e.time)}function r(){t.nodes.notifications.appendChild(a),d.focus(),t.nodes.notifications.classList.add("cdx-notification__notification-appending"),window.setTimeout(function(){t.nodes.notifications.classList.remove("cdx-notification__notification-appending")},100),o({type:c,close:i})}function i(){a.remove()}var a=null,s=null,c=null,l=null,d=null,u=function(){if(i(),"function"==typeof l)return"prompt"==c?void l(d.value):void l()},p=function(){i(),"function"==typeof s&&s()};return e&&(n(e),r()),{create:n,send:r,close:i}},e.clear=function(){t.nodes.notifications.innerHTML="",n=[]},e}({})},function(e,t){"use strict";e.exports=function(e){var t=codex.editor;return e.insertPastedContent=function(e,n){t.content.insertBlock({type:e.type,block:e.render({text:n.innerHTML})})},e.isFirstLevelBlock=function(e){return e.nodeType==t.core.nodeTypes.TAG&&e.classList.contains(t.ui.className.BLOCK_CLASSNAME)},e}({})},function(e,t,n){"use strict";e.exports=function(e){var t=n(18),o={BASIC:{tags:{p:{},a:{href:!0,target:"_blank",rel:"nofollow"},i:{},b:{},strong:{},em:{},span:{}}}};return e.Config=o,e.init=t,e}({})},function(e,t,n){var o,r;!function(i,a){o=a,r="function"==typeof o?o.call(t,n,t,e):o,!(void 0!==r&&(e.exports=r))}(this,function(){function e(e){var t=e.tags,n=Object.keys(t),o=n.map(function(e){return typeof t[e]}).every(function(e){return"object"===e||"boolean"===e||"function"===e});if(!o)throw new Error("The configuration was invalid");this.config=e}function t(e){return s.indexOf(e.nodeName)!==-1}function n(e){return c.indexOf(e.nodeName)!==-1}function o(e){return document.createTreeWalker(e,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_COMMENT,null,!1)}function r(e,t,n){return"function"==typeof e.tags[t]?e.tags[t](n):e.tags[t]}function i(e,t){return"undefined"==typeof t||"boolean"==typeof t&&!t}function a(e,t,n){var o=e.name.toLowerCase();return t!==!0&&("function"==typeof t[o]?!t[o](e.value,n):"undefined"==typeof t[o]||(t[o]===!1||"string"==typeof t[o]&&t[o]!==e.value))}var s=["P","LI","TD","TH","DIV","H1","H2","H3","H4","H5","H6","PRE"],c=["A","B","STRONG","I","EM","SUB","SUP","U","STRIKE"];return e.prototype.clean=function(e){var t=document.createElement("div");return t.innerHTML=e,this._sanitize(t),t.innerHTML},e.prototype._sanitize=function(e){var s=o(e),c=s.firstChild();if(c)do if(!c._sanitized)if(c.nodeType!==Node.TEXT_NODE){if(c.nodeType===Node.COMMENT_NODE){e.removeChild(c),this._sanitize(e);break}var l,d=n(c);d&&(l=Array.prototype.some.call(c.childNodes,t));var u=!!e.parentNode,p=t(e)&&t(c)&&u,f=c.nodeName.toLowerCase(),h=r(this.config,f,c),g=d&&l;if(g||i(c,h)||!this.config.keepNestedBlockElements&&p){if("SCRIPT"!==c.nodeName&&"STYLE"!==c.nodeName)for(;c.childNodes.length>0;)e.insertBefore(c.childNodes[0],c);e.removeChild(c),this._sanitize(e);break}for(var v=0;v=t.core.keys.LEFT&&e.keyCode<=t.core.keys.DOWN&&e.stopPropagation()},e.rusToTranslit=function(e){for(var t=["А","Б","В","Г","Д","Е","Ё","Ж","З","И","Й","К","Л","М","Н","О","П","Р","С","Т","У","Ф","Х","Ц","Ч","Ш","Щ","Ь","Ы","Ь","Э","Ю","Я"],n=["A","B","V","G","D","E","E","Zh","Z","I","Y","K","L","M","N","O","P","R","S","T","U","F","H","C","Ch","Sh","Sch","","Y","","E","Yu","Ya"],o=0;o0&&t.splice(s,1)}},e.removeAll=function(){t.map(function(t){e.remove(t.element,t.type,t.handler)})},e.get=function(t,n,o){return e.search.all(t,n,o)},e}({})},function(e,t){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};e.exports=function(e){var t=codex.editor;return e.removeNodes=function(){t.nodes.wrapper.remove(),t.nodes.notifications.remove()},e.destroyPlugins=function(){for(var e in t.tools)"function"==typeof t.tools[e].destroy&&t.tools[e].destroy()},e.destroyScripts=function(){for(var e=document.getElementsByTagName("SCRIPT"),n=0;n nodeList\n\t */\n\t renderer.appendBlocks = function (data) {\n\t\n\t var blocks = data.items;\n\t\n\t /**\n\t * Sequence of one-by-one blocks appending\n\t * Uses to save blocks order after async-handler\n\t */\n\t var nodeSequence = Promise.resolve();\n\t\n\t for (var index = 0; index < blocks.length; index++) {\n\t\n\t /** Add node to sequence at specified index */\n\t editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\n\t }\n\t };\n\t\n\t /**\n\t * Append node at specified index\n\t */\n\t renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\n\t\n\t /** We need to append node to sequence */\n\t nodeSequence\n\t\n\t /** first, get node async-aware */\n\t .then(function () {\n\t\n\t return editor.renderer.getNodeAsync(blocks, index);\n\t })\n\t\n\t /**\n\t * second, compose editor-block from JSON object\n\t */\n\t .then(editor.renderer.createBlockFromData)\n\t\n\t /**\n\t * now insert block to redactor\n\t */\n\t .then(function (blockData) {\n\t\n\t /**\n\t * blockData has 'block', 'type' and 'stretched' information\n\t */\n\t editor.content.insertBlock(blockData);\n\t\n\t /** Pass created block to next step */\n\t return blockData.block;\n\t })\n\t\n\t /** Log if something wrong with node */\n\t .catch(function (error) {\n\t\n\t editor.core.log('Node skipped while parsing because %o', 'error', error);\n\t });\n\t };\n\t\n\t /**\n\t * Asynchronously returns block data from blocksList by index\n\t * @return Promise to node\n\t */\n\t renderer.getNodeAsync = function (blocksList, index) {\n\t\n\t return Promise.resolve().then(function () {\n\t\n\t return {\n\t tool: blocksList[index],\n\t position: index\n\t };\n\t });\n\t };\n\t\n\t /**\n\t * Creates editor block by JSON-data\n\t *\n\t * @uses render method of each plugin\n\t *\n\t * @param {Object} toolData.tool\n\t * { header : {\n\t * text: '',\n\t * type: 'H3', ...\n\t * }\n\t * }\n\t * @param {Number} toolData.position - index in input-blocks array\n\t * @return {Object} with type and Element\n\t */\n\t renderer.createBlockFromData = function (toolData) {\n\t\n\t /** New parser */\n\t var block,\n\t tool = toolData.tool,\n\t pluginName = tool.type,\n\t anchor = tool.anchor,\n\t cover = tool.cover;\n\t\n\t /** Get first key of object that stores plugin name */\n\t // for (var pluginName in blockData) break;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].render != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have \\xABrender\\xBB method');\n\t }\n\t\n\t if (editor.tools[pluginName].available === false) {\n\t\n\t block = editor.draw.unavailableBlock();\n\t\n\t block.innerHTML = editor.tools[pluginName].loadingMessage;\n\t\n\t /**\n\t * Saver will extract data from initial block data by position in array\n\t */\n\t block.dataset.inputPosition = toolData.position;\n\t } else {\n\t\n\t /** New Parser */\n\t block = editor.tools[pluginName].render(tool.data);\n\t }\n\t\n\t /** is first-level block stretched */\n\t var stretched = editor.tools[pluginName].isStretched || false;\n\t\n\t /** Retrun type and block */\n\t return {\n\t type: pluginName,\n\t block: block,\n\t stretched: stretched,\n\t cover: cover,\n\t anchor: anchor\n\t };\n\t };\n\t\n\t return renderer;\n\t}({});\n\n/***/ },\n/* 6 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Saver\n\t *\n\t * @author Codex Team\n\t * @version 1.0.2\n\t */\n\t\n\tmodule.exports = function (saver) {\n\t\n\t var editor = codex.editor;\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 anchor = block.dataset.anchor;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].save != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have save method');\n\t }\n\t\n\t /** Result saver */\n\t var blockContent = block.childNodes[0],\n\t pluginsContent = blockContent.childNodes[0],\n\t savedData,\n\t position,\n\t output,\n\t coverFlag = false;\n\t\n\t /** If plugin wasn't available then return data from cache */\n\t if (editor.tools[pluginName].available === false) {\n\t\n\t position = pluginsContent.dataset.inputPosition;\n\t\n\t savedData = codex.editor.state.blocks.items[position].data;\n\t coverFlag = codex.editor.state.blocks.items[position].cover;\n\t anchor = codex.editor.state.blocks.items[position].anchor;\n\t } else {\n\t\n\t savedData = editor.tools[pluginName].save(pluginsContent);\n\t coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t\n\t if (editor.tools[pluginName].validate) {\n\t\n\t var result = editor.tools[pluginName].validate(savedData);\n\t\n\t /**\n\t * Do not allow invalid data\n\t */\n\t if (!result) return;\n\t }\n\t }\n\t\n\t output = {\n\t type: pluginName,\n\t anchor: anchor,\n\t data: savedData\n\t };\n\t\n\t /** Marks Blocks that will be in main page */\n\t output.cover = coverFlag;\n\t\n\t editor.state.jsonOutput.push(output);\n\t };\n\t\n\t return saver;\n\t}({});\n\n/***/ },\n/* 7 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Content Module\n\t * Works with DOM\n\t *\n\t * @author Codex Team\n\t * @version 1.3.12\n\t */\n\t\n\tmodule.exports = function (content) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Links to current active block\n\t * @type {null | Element}\n\t */\n\t content.currentNode = null;\n\t\n\t /**\n\t * clicked in redactor area\n\t * @type {null | Boolean}\n\t */\n\t content.editorAreaHightlighted = null;\n\t\n\t /**\n\t * 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 if (targetBlock.classList.contains(editor.ui.className.BLOCK_WITH_ANCHOR)) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t\n\t /**\n\t * Saving anchor\n\t */\n\t newBlock.dataset.anchor = targetBlock.dataset.anchor;\n\t\n\t /** Replacing */\n\t editor.nodes.redactor.replaceChild(newBlock, targetBlock);\n\t\n\t /**\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 anchor = blockData.anchor,\n\t isStretched = blockData.stretched;\n\t\n\t var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);\n\t\n\t if (cover === true) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t }\n\t\n\t if (anchor) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t\n\t if (workingBlock) {\n\t\n\t editor.core.insertAfter(workingBlock, newBlock);\n\t } else {\n\t\n\t /**\n\t * If redactor is empty, append as first child\n\t */\n\t editor.nodes.redactor.appendChild(newBlock);\n\t }\n\t\n\t /**\n\t * Block handler\n\t */\n\t editor.ui.addBlockHandlers(newBlock);\n\t\n\t /**\n\t * Set new node as current\n\t */\n\t editor.content.workingNodeChanged(newBlock);\n\t\n\t /**\n\t * Save changes\n\t */\n\t editor.ui.saveInputs();\n\t\n\t if (needPlaceCaret) {\n\t\n\t /**\n\t * If we don't know input index then we set default value -1\n\t */\n\t var currentInputIndex = editor.caret.getCurrentInputIndex() || -1;\n\t\n\t if (currentInputIndex == -1) {\n\t\n\t var editableElement = newBlock.querySelector('[contenteditable]'),\n\t emptyText = document.createTextNode('');\n\t\n\t editableElement.appendChild(emptyText);\n\t editor.caret.set(editableElement, 0, 0);\n\t\n\t editor.toolbar.move();\n\t editor.toolbar.showPlusButton();\n\t } else {\n\t\n\t if (currentInputIndex === editor.state.inputs.length - 1) return;\n\t\n\t /** Timeout for browsers execution */\n\t window.setTimeout(function () {\n\t\n\t /** Setting to the new input */\n\t editor.caret.setToNextBlock(currentInputIndex);\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t }, 10);\n\t }\n\t }\n\t\n\t /**\n\t * Block is inserted, wait for new click that defined focusing on editors area\n\t * @type {boolean}\n\t */\n\t content.editorAreaHightlighted = false;\n\t };\n\t\n\t /**\n\t * Replaces blocks with saving content\n\t * @protected\n\t * @param {Element} noteToReplace\n\t * @param {Element} newNode\n\t * @param {Element} blockType\n\t */\n\t content.switchBlock = function (blockToReplace, newBlock, tool) {\n\t\n\t tool = tool || editor.content.currentNode.dataset.tool;\n\t var newBlockComposed = 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, anchor) {\n\t\n\t var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),\n\t blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});\n\t\n\t blockContent.appendChild(block);\n\t newBlock.appendChild(blockContent);\n\t\n\t if (isStretched) {\n\t\n\t blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED);\n\t }\n\t\n\t newBlock.dataset.tool = tool;\n\t newBlock.dataset.anchor = anchor || '';\n\t return newBlock;\n\t };\n\t\n\t /**\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 /**\n\t * Finds closest Contenteditable parent from Element\n\t * @param {Element} node element looking from\n\t * @return {Element} node contenteditable\n\t */\n\t content.getEditableParent = function (node) {\n\t\n\t while (node && node.contentEditable != 'true') {\n\t\n\t node = node.parentNode;\n\t }\n\t\n\t return node;\n\t };\n\t\n\t return content;\n\t}({});\n\n/***/ },\n/* 8 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor toolbar module\n\t *\n\t * Contains:\n\t * - Inline toolbox\n\t * - Toolbox within plus button\n\t * - Settings section\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (toolbar) {\n\t\n\t var editor = codex.editor;\n\t\n\t toolbar.settings = __webpack_require__(9);\n\t toolbar.inline = __webpack_require__(10);\n\t toolbar.toolbox = __webpack_require__(11);\n\t\n\t /**\n\t * Margin between focused node and toolbar\n\t */\n\t toolbar.defaultToolbarHeight = 49;\n\t\n\t toolbar.defaultOffset = 34;\n\t\n\t toolbar.opened = false;\n\t\n\t toolbar.current = null;\n\t\n\t /**\n\t * @protected\n\t */\n\t toolbar.open = function () {\n\t\n\t if (editor.hideToolbar) {\n\t\n\t return;\n\t }\n\t\n\t editor.nodes.toolbar.classList.add('opened');\n\t this.opened = true;\n\t };\n\t\n\t /**\n\t * @protected\n\t */\n\t toolbar.close = function () {\n\t\n\t editor.nodes.toolbar.classList.remove('opened');\n\t\n\t toolbar.opened = false;\n\t toolbar.current = null;\n\t\n\t for (var button in editor.nodes.toolbarButtons) {\n\t\n\t editor.nodes.toolbarButtons[button].classList.remove('selected');\n\t }\n\t\n\t /** Close toolbox when toolbar is not displayed */\n\t editor.toolbar.toolbox.close();\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t toolbar.toggle = function () {\n\t\n\t if (!this.opened) {\n\t\n\t this.open();\n\t } else {\n\t\n\t this.close();\n\t }\n\t };\n\t\n\t toolbar.hidePlusButton = function () {\n\t\n\t editor.nodes.plusButton.classList.add('hide');\n\t };\n\t\n\t toolbar.showPlusButton = function () {\n\t\n\t editor.nodes.plusButton.classList.remove('hide');\n\t };\n\t\n\t /**\n\t * Moving toolbar to the specified node\n\t */\n\t toolbar.move = function () {\n\t\n\t /** Close Toolbox when we move toolbar */\n\t editor.toolbar.toolbox.close();\n\t\n\t if (!editor.content.currentNode) {\n\t\n\t return;\n\t }\n\t\n\t var newYCoordinate = editor.content.currentNode.offsetTop - editor.toolbar.defaultToolbarHeight / 2 + editor.toolbar.defaultOffset;\n\t\n\t editor.nodes.toolbar.style.transform = 'translate3D(0, ' + Math.floor(newYCoordinate) + 'px, 0)';\n\t\n\t /** Close trash actions */\n\t editor.toolbar.settings.hideRemoveActions();\n\t };\n\t\n\t return toolbar;\n\t}({});\n\n/***/ },\n/* 9 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Toolbar settings\n\t *\n\t * @version 1.0.4\n\t */\n\t\n\tmodule.exports = function (settings) {\n\t\n\t var editor = codex.editor;\n\t\n\t settings.opened = false;\n\t\n\t settings.setting = null;\n\t settings.actions = null;\n\t\n\t settings.cover = null;\n\t\n\t /**\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 editor.anchors.settingsOpened(editor.content.currentNode);\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, anchorInput;\n\t\n\t /** Clear block and append initialized settings */\n\t editor.nodes.defaultSettings.innerHTML = '';\n\t\n\t /** Init all default setting buttons */\n\t feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();\n\t anchorInput = editor.toolbar.settings.makeAnchorInput();\n\t\n\t /**\n\t * Fill defaultSettings\n\t */\n\t\n\t /**\n\t * Input for anchor for block\n\t */\n\t editor.nodes.defaultSettings.appendChild(anchorInput);\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: 'Вывести в ленте'\n\t };\n\t } else {\n\t\n\t data = {\n\t innerHTML: 'Не выводить в ленте'\n\t };\n\t }\n\t\n\t setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\n\t editor.listeners.add(setting, 'click', editor.toolbar.settings.updateFeedMode, false);\n\t\n\t return setting;\n\t };\n\t\n\t /**\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 settings.makeAnchorInput = function () {\n\t\n\t var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),\n\t hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),\n\t anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });\n\t\n\t editor.listeners.add(anchor, 'keydown', editor.anchors.keyDownOnAnchorInput);\n\t editor.listeners.add(anchor, 'keyup', editor.anchors.keyUpOnAnchorInput);\n\t editor.listeners.add(anchor, 'input', editor.anchors.anchorChanged);\n\t editor.listeners.add(anchor, 'blur', editor.anchors.anchorChanged);\n\t\n\t anchorWrapper.appendChild(hash);\n\t anchorWrapper.appendChild(anchor);\n\t\n\t editor.anchors.input = anchor;\n\t\n\t return anchorWrapper;\n\t };\n\t\n\t /**\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: '' }),\n\t actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\n\t confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent: 'Удалить блок' }),\n\t cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent: 'Отмена' });\n\t\n\t editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\n\t\n\t editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\n\t\n\t editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\n\t\n\t actionWrapper.appendChild(confirmAction);\n\t actionWrapper.appendChild(cancelAction);\n\t\n\t removeBlockWrapper.appendChild(settingButton);\n\t removeBlockWrapper.appendChild(actionWrapper);\n\t\n\t /** Save setting */\n\t editor.toolbar.settings.setting = settingButton;\n\t editor.toolbar.settings.actions = actionWrapper;\n\t\n\t return removeBlockWrapper;\n\t };\n\t\n\t settings.removeButtonClicked = function () {\n\t\n\t var action = editor.toolbar.settings.actions;\n\t\n\t if (action.classList.contains('opened')) {\n\t\n\t editor.toolbar.settings.hideRemoveActions();\n\t } else {\n\t\n\t editor.toolbar.settings.showRemoveActions();\n\t }\n\t\n\t editor.toolbar.toolbox.close();\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t settings.cancelRemovingRequest = function () {\n\t\n\t editor.toolbar.settings.actions.classList.remove('opened');\n\t };\n\t\n\t settings.confirmRemovingRequest = function () {\n\t\n\t var currentBlock = editor.content.currentNode,\n\t firstLevelBlocksCount;\n\t\n\t currentBlock.remove();\n\t\n\t firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\t\n\t /**\n\t * If all blocks are removed\n\t */\n\t if (firstLevelBlocksCount === 0) {\n\t\n\t /** update currentNode variable */\n\t editor.content.currentNode = null;\n\t\n\t /** Inserting new empty initial block */\n\t editor.ui.addInitialBlock();\n\t }\n\t\n\t editor.ui.saveInputs();\n\t\n\t editor.toolbar.close();\n\t };\n\t\n\t settings.showRemoveActions = function () {\n\t\n\t editor.toolbar.settings.actions.classList.add('opened');\n\t };\n\t\n\t settings.hideRemoveActions = function () {\n\t\n\t editor.toolbar.settings.actions.classList.remove('opened');\n\t };\n\t\n\t return settings;\n\t}({});\n\n/***/ },\n/* 10 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Inline toolbar\n\t *\n\t * Contains from tools:\n\t * Bold, Italic, Underline and Anchor\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (inline) {\n\t\n\t var editor = codex.editor;\n\t\n\t inline.buttonsOpened = null;\n\t inline.actionsOpened = null;\n\t inline.wrappersOffset = null;\n\t\n\t /**\n\t * saving selection that need for execCommand for styling\n\t *\n\t */\n\t inline.storedSelection = null;\n\t\n\t /**\n\t * @protected\n\t *\n\t * Open inline toobar\n\t */\n\t inline.show = function () {\n\t\n\t var currentNode = editor.content.currentNode,\n\t tool = currentNode.dataset.tool,\n\t plugin;\n\t\n\t /**\n\t * tool allowed to open inline toolbar\n\t */\n\t plugin = editor.tools[tool];\n\t\n\t if (!plugin.showInlineToolbar) return;\n\t\n\t var selectedText = inline.getSelectionText(),\n\t toolbar = editor.nodes.inlineToolbar.wrapper;\n\t\n\t if (selectedText.length > 0) {\n\t\n\t /** Move toolbar and open */\n\t editor.toolbar.inline.move();\n\t\n\t /** Open inline toolbar */\n\t toolbar.classList.add('opened');\n\t\n\t /** show buttons of inline toolbar */\n\t editor.toolbar.inline.showButtons();\n\t }\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Closes inline toolbar\n\t */\n\t inline.close = function () {\n\t\n\t var toolbar = editor.nodes.inlineToolbar.wrapper;\n\t\n\t toolbar.classList.remove('opened');\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Moving toolbar\n\t */\n\t inline.move = function () {\n\t\n\t if (!this.wrappersOffset) {\n\t\n\t this.wrappersOffset = this.getWrappersOffset();\n\t }\n\t\n\t var coords = this.getSelectionCoords(),\n\t defaultOffset = 0,\n\t toolbar = editor.nodes.inlineToolbar.wrapper,\n\t newCoordinateX,\n\t newCoordinateY;\n\t\n\t if (toolbar.offsetHeight === 0) {\n\t\n\t defaultOffset = 40;\n\t }\n\t\n\t newCoordinateX = coords.x - this.wrappersOffset.left;\n\t newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;\n\t\n\t toolbar.style.transform = 'translate3D(' + Math.floor(newCoordinateX) + 'px, ' + Math.floor(newCoordinateY) + 'px, 0)';\n\t\n\t /** Close everything */\n\t editor.toolbar.inline.closeButtons();\n\t editor.toolbar.inline.closeAction();\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Tool Clicked\n\t */\n\t\n\t inline.toolClicked = function (event, type) {\n\t\n\t /**\n\t * For simple tools we use default browser function\n\t * For more complicated tools, we should write our own behavior\n\t */\n\t switch (type) {\n\t case 'createLink':\n\t editor.toolbar.inline.createLinkAction(event, type);break;\n\t default:\n\t editor.toolbar.inline.defaultToolAction(type);break;\n\t }\n\t\n\t /**\n\t * highlight buttons\n\t * after making some action\n\t */\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Saving wrappers offset in DOM\n\t */\n\t inline.getWrappersOffset = function () {\n\t\n\t var wrapper = editor.nodes.wrapper,\n\t offset = this.getOffset(wrapper);\n\t\n\t this.wrappersOffset = offset;\n\t return offset;\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Calculates offset of DOM element\n\t *\n\t * @param el\n\t * @returns {{top: number, left: number}}\n\t */\n\t inline.getOffset = function (el) {\n\t\n\t var _x = 0;\n\t var _y = 0;\n\t\n\t while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {\n\t\n\t _x += el.offsetLeft + el.clientLeft;\n\t _y += el.offsetTop + el.clientTop;\n\t el = el.offsetParent;\n\t }\n\t return { top: _y, left: _x };\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Calculates position of selected text\n\t * @returns {{x: number, y: number}}\n\t */\n\t inline.getSelectionCoords = function () {\n\t\n\t var sel = document.selection,\n\t range;\n\t var x = 0,\n\t y = 0;\n\t\n\t if (sel) {\n\t\n\t if (sel.type != 'Control') {\n\t\n\t range = sel.createRange();\n\t range.collapse(true);\n\t x = range.boundingLeft;\n\t y = range.boundingTop;\n\t }\n\t } else if (window.getSelection) {\n\t\n\t sel = window.getSelection();\n\t\n\t if (sel.rangeCount) {\n\t\n\t range = sel.getRangeAt(0).cloneRange();\n\t if (range.getClientRects) {\n\t\n\t range.collapse(true);\n\t var rect = range.getClientRects()[0];\n\t\n\t if (!rect) {\n\t\n\t return;\n\t }\n\t\n\t x = rect.left;\n\t y = rect.top;\n\t }\n\t }\n\t }\n\t return { x: x, y: y };\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Returns selected text as String\n\t * @returns {string}\n\t */\n\t inline.getSelectionText = function () {\n\t\n\t var selectedText = '';\n\t\n\t // all modern browsers and IE9+\n\t if (window.getSelection) {\n\t\n\t selectedText = window.getSelection().toString();\n\t }\n\t\n\t return selectedText;\n\t };\n\t\n\t /** Opens buttons block */\n\t inline.showButtons = function () {\n\t\n\t var buttons = editor.nodes.inlineToolbar.buttons;\n\t\n\t buttons.classList.add('opened');\n\t\n\t editor.toolbar.inline.buttonsOpened = true;\n\t\n\t /** highlight buttons */\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\t };\n\t\n\t /** Makes buttons disappear */\n\t inline.closeButtons = function () {\n\t\n\t var buttons = editor.nodes.inlineToolbar.buttons;\n\t\n\t buttons.classList.remove('opened');\n\t\n\t editor.toolbar.inline.buttonsOpened = false;\n\t };\n\t\n\t /** Open buttons defined action if exist */\n\t inline.showActions = function () {\n\t\n\t var action = editor.nodes.inlineToolbar.actions;\n\t\n\t action.classList.add('opened');\n\t\n\t editor.toolbar.inline.actionsOpened = true;\n\t };\n\t\n\t /** Close actions block */\n\t inline.closeAction = function () {\n\t\n\t var action = editor.nodes.inlineToolbar.actions;\n\t\n\t action.innerHTML = '';\n\t action.classList.remove('opened');\n\t editor.toolbar.inline.actionsOpened = false;\n\t };\n\t\n\t /**\n\t * Callback for keydowns in inline toolbar \"Insert link...\" input\n\t */\n\t var inlineToolbarAnchorInputKeydown_ = function inlineToolbarAnchorInputKeydown_(event) {\n\t\n\t if (event.keyCode != editor.core.keys.ENTER) {\n\t\n\t return;\n\t }\n\t\n\t var editable = editor.content.currentNode,\n\t storedSelection = editor.toolbar.inline.storedSelection;\n\t\n\t editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\t editor.toolbar.inline.setAnchor(this.value);\n\t\n\t /**\n\t * Preventing events that will be able to happen\n\t */\n\t event.preventDefault();\n\t event.stopImmediatePropagation();\n\t\n\t editor.toolbar.inline.clearRange();\n\t };\n\t\n\t /** Action for link creation or for setting anchor */\n\t inline.createLinkAction = function (event) {\n\t\n\t var isActive = this.isLinkActive();\n\t\n\t var editable = editor.content.currentNode,\n\t storedSelection = editor.toolbar.inline.saveSelection(editable);\n\t\n\t /** Save globally selection */\n\t editor.toolbar.inline.storedSelection = storedSelection;\n\t\n\t if (isActive) {\n\t\n\t /**\n\t * Changing stored selection. if we want to remove anchor from word\n\t * we should remove anchor from whole word, not only selected part.\n\t * The solution is than we get the length of current link\n\t * Change start position to - end of selection minus length of anchor\n\t */\n\t editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\t\n\t editor.toolbar.inline.defaultToolAction('unlink');\n\t } else {\n\t\n\t /** Create input and close buttons */\n\t var action = editor.draw.inputForLink();\n\t\n\t editor.nodes.inlineToolbar.actions.appendChild(action);\n\t\n\t editor.toolbar.inline.closeButtons();\n\t editor.toolbar.inline.showActions();\n\t\n\t /**\n\t * focus to input\n\t * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\n\t * Prevents event after showing input and when we need to focus an input which is in unexisted form\n\t */\n\t action.focus();\n\t event.preventDefault();\n\t\n\t /** Callback to link action */\n\t editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);\n\t }\n\t };\n\t\n\t inline.isLinkActive = function () {\n\t\n\t var isActive = false;\n\t\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\n\t\n\t var dataType = tool.dataset.type;\n\t\n\t if (dataType == 'link' && tool.classList.contains('hightlighted')) {\n\t\n\t isActive = true;\n\t }\n\t });\n\t\n\t return isActive;\n\t };\n\t\n\t /** default action behavior of tool */\n\t inline.defaultToolAction = function (type) {\n\t\n\t document.execCommand(type, false, null);\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Sets URL\n\t *\n\t * @param {String} url - URL\n\t */\n\t inline.setAnchor = function (url) {\n\t\n\t document.execCommand('createLink', false, url);\n\t\n\t /** Close after URL inserting */\n\t editor.toolbar.inline.closeAction();\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Saves selection\n\t */\n\t inline.saveSelection = function (containerEl) {\n\t\n\t var range = window.getSelection().getRangeAt(0),\n\t preSelectionRange = range.cloneRange(),\n\t start;\n\t\n\t preSelectionRange.selectNodeContents(containerEl);\n\t preSelectionRange.setEnd(range.startContainer, range.startOffset);\n\t\n\t start = preSelectionRange.toString().length;\n\t\n\t return {\n\t start: start,\n\t end: start + range.toString().length\n\t };\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Sets to previous selection (Range)\n\t *\n\t * @param {Element} containerEl - editable element where we restore range\n\t * @param {Object} savedSel - range basic information to restore\n\t */\n\t inline.restoreSelection = function (containerEl, savedSel) {\n\t\n\t var range = document.createRange(),\n\t charIndex = 0;\n\t\n\t range.setStart(containerEl, 0);\n\t range.collapse(true);\n\t\n\t var nodeStack = [containerEl],\n\t node,\n\t foundStart = false,\n\t stop = false,\n\t nextCharIndex;\n\t\n\t while (!stop && (node = nodeStack.pop())) {\n\t\n\t if (node.nodeType == 3) {\n\t\n\t nextCharIndex = charIndex + node.length;\n\t\n\t if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\n\t\n\t range.setStart(node, savedSel.start - charIndex);\n\t foundStart = true;\n\t }\n\t if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\n\t\n\t range.setEnd(node, savedSel.end - charIndex);\n\t stop = true;\n\t }\n\t charIndex = nextCharIndex;\n\t } else {\n\t\n\t var i = node.childNodes.length;\n\t\n\t while (i--) {\n\t\n\t nodeStack.push(node.childNodes[i]);\n\t }\n\t }\n\t }\n\t\n\t var sel = window.getSelection();\n\t\n\t sel.removeAllRanges();\n\t sel.addRange(range);\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Removes all ranges from window selection\n\t */\n\t inline.clearRange = function () {\n\t\n\t var selection = window.getSelection();\n\t\n\t selection.removeAllRanges();\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * sets or removes hightlight\n\t */\n\t inline.hightlight = function (tool) {\n\t\n\t var dataType = tool.dataset.type;\n\t\n\t if (document.queryCommandState(dataType)) {\n\t\n\t editor.toolbar.inline.setButtonHighlighted(tool);\n\t } else {\n\t\n\t editor.toolbar.inline.removeButtonsHighLight(tool);\n\t }\n\t\n\t /**\n\t *\n\t * hightlight for anchors\n\t */\n\t var selection = window.getSelection(),\n\t tag = selection.anchorNode.parentNode;\n\t\n\t if (tag.tagName == 'A' && dataType == 'link') {\n\t\n\t editor.toolbar.inline.setButtonHighlighted(tool);\n\t }\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Mark button if text is already executed\n\t */\n\t inline.setButtonHighlighted = function (button) {\n\t\n\t button.classList.add('hightlighted');\n\t\n\t /** At link tool we also change icon */\n\t if (button.dataset.type == 'link') {\n\t\n\t var icon = button.childNodes[0];\n\t\n\t icon.classList.remove('ce-icon-link');\n\t icon.classList.add('ce-icon-unlink');\n\t }\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Removes hightlight\n\t */\n\t inline.removeButtonsHighLight = function (button) {\n\t\n\t button.classList.remove('hightlighted');\n\t\n\t /** At link tool we also change icon */\n\t if (button.dataset.type == 'link') {\n\t\n\t var icon = button.childNodes[0];\n\t\n\t icon.classList.remove('ce-icon-unlink');\n\t icon.classList.add('ce-icon-link');\n\t }\n\t };\n\t\n\t return inline;\n\t}({});\n\n/***/ },\n/* 11 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor toolbox\n\t *\n\t * All tools be able to appended here\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (toolbox) {\n\t\n\t var editor = codex.editor;\n\t\n\t toolbox.opened = false;\n\t\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/* 12 */\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\t\n\tmodule.exports = function (callbacks) {\n\t\n\t var editor = codex.editor;\n\t\n\t callbacks.globalKeydown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.redactorKeyDown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.TAB:\n\t editor.callback.tabKeyPressed(event);break;\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressedOnRedactorZone(event);break;\n\t case editor.core.keys.ESC:\n\t editor.callback.escapeKeyPressed(event);break;\n\t default:\n\t editor.callback.defaultKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.globalKeyup = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.UP:\n\t case editor.core.keys.LEFT:\n\t case editor.core.keys.RIGHT:\n\t case editor.core.keys.DOWN:\n\t editor.callback.arrowKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.tabKeyPressed = function (event) {\n\t\n\t var blockIsEmpty = !editor.content.currentNode.textContent.trim();\n\t\n\t if (!blockIsEmpty) {\n\t\n\t return;\n\t }\n\t\n\t if (!editor.toolbar.opened) {\n\t\n\t editor.toolbar.open();\n\t }\n\t\n\t if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\t\n\t editor.toolbar.toolbox.open();\n\t } else {\n\t\n\t editor.toolbar.toolbox.leaf();\n\t }\n\t\n\t event.preventDefault();\n\t };\n\t\n\t /**\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

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 if (!inputIsEmpty) {\n\t\n\t /** Mark current block */\n\t editor.content.markBlock();\n\t }\n\t\n\t if (isInitialType && inputIsEmpty) {\n\t\n\t /** Show plus button */\n\t editor.toolbar.showPlusButton();\n\t }\n\t };\n\t\n\t /**\n\t * This method allows to define, is caret in contenteditable element or not.\n\t * 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 var editableParent = editor.content.getEditableParent(event.target),\n\t firstLevelBlock = editor.content.getFirstLevelBlock(event.target);\n\t\n\t /** Allow paste when event target placed in Editable element */\n\t if (!editableParent) {\n\t\n\t return;\n\t }\n\t\n\t /** get html pasted data - dirty data */\n\t var data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain');\n\t\n\t /** Temporary DIV that is used to work with childs as arrays item */\n\t var div = editor.draw.node('DIV', '', {}),\n\t cleaner = new editor.sanitizer.init(editor.sanitizer.Config.BASIC),\n\t cleanData,\n\t fragment;\n\t\n\t /** Create fragment, that we paste to range after proccesing */\n\t fragment = document.createDocumentFragment();\n\t\n\t cleanData = cleaner.clean(data);\n\t\n\t div.innerHTML = cleanData;\n\t\n\t var node, lastNode;\n\t\n\t /**\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 if (editor.tools[firstLevelBlock.dataset.tool].allowRenderOnPaste) {\n\t\n\t if (editor.paste.pasted(event)) return;\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/* 13 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Draw module\n\t *\n\t * @author Codex Team\n\t * @version 1.0.\n\t */\n\t\n\tmodule.exports = function (draw) {\n\t\n\t /**\n\t * Base editor wrapper\n\t */\n\t draw.wrapper = function () {\n\t\n\t var wrapper = document.createElement('div');\n\t\n\t wrapper.className += 'codex-editor';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * Content-editable holder\n\t */\n\t draw.redactor = function () {\n\t\n\t var redactor = document.createElement('div');\n\t\n\t redactor.className += 'ce-redactor';\n\t\n\t return redactor;\n\t };\n\t\n\t draw.ceBlock = function () {\n\t\n\t var block = document.createElement('DIV');\n\t\n\t block.className += 'ce_block';\n\t\n\t return block;\n\t };\n\t\n\t /**\n\t * Empty toolbar with toggler\n\t */\n\t draw.toolbar = function () {\n\t\n\t var bar = document.createElement('div');\n\t\n\t bar.className += 'ce-toolbar';\n\t\n\t return bar;\n\t };\n\t\n\t draw.toolbarContent = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.classList.add('ce-toolbar__content');\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * Inline toolbar\n\t */\n\t draw.inlineToolbar = function () {\n\t\n\t var bar = document.createElement('DIV');\n\t\n\t bar.className += 'ce-toolbar-inline';\n\t\n\t return bar;\n\t };\n\t\n\t /**\n\t * Wrapper for inline toobar buttons\n\t */\n\t draw.inlineToolbarButtons = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.className += 'ce-toolbar-inline__buttons';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * For some actions\n\t */\n\t draw.inlineToolbarActions = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.className += 'ce-toolbar-inline__actions';\n\t\n\t return wrapper;\n\t };\n\t\n\t draw.inputForLink = function () {\n\t\n\t var input = document.createElement('INPUT');\n\t\n\t input.type = 'input';\n\t input.className += 'inputForLink';\n\t input.placeholder = 'Вставьте ссылку ...';\n\t input.setAttribute('form', 'defaultForm');\n\t\n\t input.setAttribute('autofocus', 'autofocus');\n\t\n\t return input;\n\t };\n\t\n\t /**\n\t * @todo Desc\n\t */\n\t draw.blockButtons = function () {\n\t\n\t var block = document.createElement('div');\n\t\n\t block.className += 'ce-toolbar__actions';\n\t\n\t return block;\n\t };\n\t\n\t /**\n\t * Block settings panel\n\t */\n\t draw.blockSettings = function () {\n\t\n\t var settings = document.createElement('div');\n\t\n\t settings.className += 'ce-settings';\n\t\n\t return settings;\n\t };\n\t\n\t draw.defaultSettings = function () {\n\t\n\t var div = document.createElement('div');\n\t\n\t div.classList.add('ce-settings_default');\n\t\n\t return div;\n\t };\n\t\n\t draw.pluginsSettings = function () {\n\t\n\t var div = document.createElement('div');\n\t\n\t div.classList.add('ce-settings_plugin');\n\t\n\t return div;\n\t };\n\t\n\t draw.plusButton = function () {\n\t\n\t var button = document.createElement('span');\n\t\n\t button.className = 'ce-toolbar__plus';\n\t // button.innerHTML = '';\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 = '';\n\t\n\t return toggler;\n\t };\n\t\n\t /**\n\t * Redactor tools wrapper\n\t */\n\t\n\t draw.toolbox = function () {\n\t\n\t var wrapper = document.createElement('div');\n\t\n\t wrapper.className = 'ce-toolbar__tools';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Draws tool buttons for toolbox\n\t *\n\t * @param {String} type\n\t * @param {String} classname\n\t * @returns {Element}\n\t */\n\t draw.toolbarButton = function (type, classname) {\n\t\n\t var button = document.createElement('li'),\n\t toolIcon = document.createElement('i'),\n\t toolTitle = document.createElement('span');\n\t\n\t button.dataset.type = type;\n\t button.setAttribute('title', type);\n\t\n\t toolIcon.classList.add(classname);\n\t toolTitle.classList.add('ce_toolbar_tools--title');\n\t\n\t button.appendChild(toolIcon);\n\t button.appendChild(toolTitle);\n\t\n\t return button;\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Draws tools for inline toolbar\n\t *\n\t * @param {String} type\n\t * @param {String} classname\n\t */\n\t draw.toolbarButtonInline = function (type, classname) {\n\t\n\t var button = document.createElement('BUTTON'),\n\t toolIcon = document.createElement('I');\n\t\n\t button.type = 'button';\n\t button.dataset.type = type;\n\t toolIcon.classList.add(classname);\n\t\n\t button.appendChild(toolIcon);\n\t\n\t return button;\n\t };\n\t\n\t /**\n\t * Redactor block\n\t */\n\t draw.block = function (tagName, content) {\n\t\n\t var node = document.createElement(tagName);\n\t\n\t node.innerHTML = content || '';\n\t\n\t return node;\n\t };\n\t\n\t /**\n\t * Creates Node with passed tagName and className\n\t * @param {string} tagName\n\t * @param {string} className\n\t * @param {object} properties - allow to assign properties\n\t */\n\t draw.node = function (tagName, className, properties) {\n\t\n\t var el = document.createElement(tagName);\n\t\n\t if (className) el.className = className;\n\t\n\t if (properties) {\n\t\n\t for (var name in properties) {\n\t\n\t el[name] = properties[name];\n\t }\n\t }\n\t\n\t return el;\n\t };\n\t\n\t /**\n\t * Unavailable plugin block\n\t */\n\t draw.unavailableBlock = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.classList.add('cdx-unavailable-block');\n\t\n\t return wrapper;\n\t };\n\t\n\t return draw;\n\t}({});\n\n/***/ },\n/* 14 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Caret Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (caret) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * @var {int} InputIndex - editable element in DOM\n\t */\n\t caret.inputIndex = null;\n\t\n\t /**\n\t * @var {int} offset - caret position in a text node.\n\t */\n\t caret.offset = null;\n\t\n\t /**\n\t * @var {int} focusedNodeIndex - we get index of child node from first-level block\n\t */\n\t caret.focusedNodeIndex = null;\n\t\n\t /**\n\t * Creates Document Range and sets caret to the element.\n\t * @protected\n\t * @uses caret.save — if you need to save caret position\n\t * @param {Element} el - Changed Node.\n\t */\n\t caret.set = function (el, index, offset) {\n\t\n\t offset = offset || caret.offset || 0;\n\t index = index || caret.focusedNodeIndex || 0;\n\t\n\t var childs = el.childNodes,\n\t nodeToSet;\n\t\n\t if (childs.length === 0) {\n\t\n\t nodeToSet = el;\n\t } else {\n\t\n\t nodeToSet = childs[index];\n\t }\n\t\n\t /** If Element is INPUT */\n\t if (el.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/* 15 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Notification Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (notifications) {\n\t\n\t var editor = codex.editor;\n\t\n\t var queue = [];\n\t\n\t var addToQueue = function addToQueue(settings) {\n\t\n\t queue.push(settings);\n\t\n\t var index = 0;\n\t\n\t while (index < queue.length && queue.length > 5) {\n\t\n\t if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n\t\n\t index++;\n\t continue;\n\t }\n\t\n\t queue[index].close();\n\t queue.splice(index, 1);\n\t }\n\t };\n\t\n\t notifications.createHolder = function () {\n\t\n\t var holder = editor.draw.node('DIV', 'cdx-notifications-block');\n\t\n\t editor.nodes.notifications = document.body.appendChild(holder);\n\t\n\t return holder;\n\t };\n\t\n\t /**\n\t * Error notificator. Shows block with message\n\t * @protected\n\t */\n\t notifications.errorThrown = function (errorMsg, event) {\n\t\n\t editor.notifications.notification({ message: 'This action is not available currently', type: event.type });\n\t };\n\t\n\t /**\n\t *\n\t * Appends notification\n\t *\n\t * settings = {\n\t * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\n\t * message - notification message\n\t * okMsg - confirm button text (default - 'Ok')\n\t * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\n\t * confirm - function-handler for ok button click\n\t * cancel - function-handler for cancel button click. Only for confirm and prompt types\n\t * time - time (in seconds) after which notification will close (default - 10s)\n\t * }\n\t *\n\t * @param settings\n\t */\n\t notifications.notification = function (constructorSettings) {\n\t\n\t /** Private vars and methods */\n\t var notification = null,\n\t cancel = null,\n\t type = null,\n\t confirm = null,\n\t inputField = null;\n\t\n\t var confirmHandler = function confirmHandler() {\n\t\n\t close();\n\t\n\t if (typeof confirm !== 'function') {\n\t\n\t return;\n\t }\n\t\n\t if (type == 'prompt') {\n\t\n\t confirm(inputField.value);\n\t return;\n\t }\n\t\n\t confirm();\n\t };\n\t\n\t var cancelHandler = function cancelHandler() {\n\t\n\t close();\n\t\n\t if (typeof cancel !== 'function') {\n\t\n\t return;\n\t }\n\t\n\t cancel();\n\t };\n\t\n\t /** Public methods */\n\t function create(settings) {\n\t\n\t if (!(settings && settings.message)) {\n\t\n\t editor.core.log('Can\\'t create notification. Message is missed');\n\t return;\n\t }\n\t\n\t settings.type = settings.type || 'alert';\n\t settings.time = settings.time * 1000 || 10000;\n\t\n\t var wrapper = editor.draw.node('DIV', 'cdx-notification'),\n\t message = editor.draw.node('DIV', 'cdx-notification__message'),\n\t input = editor.draw.node('INPUT', 'cdx-notification__input'),\n\t okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\n\t cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\n\t\n\t message.textContent = settings.message;\n\t okBtn.textContent = settings.okMsg || 'ОК';\n\t cancelBtn.textContent = settings.cancelMsg || 'Отмена';\n\t\n\t editor.listeners.add(okBtn, 'click', confirmHandler);\n\t editor.listeners.add(cancelBtn, 'click', cancelHandler);\n\t\n\t wrapper.appendChild(message);\n\t\n\t if (settings.type == 'prompt') {\n\t\n\t wrapper.appendChild(input);\n\t }\n\t\n\t wrapper.appendChild(okBtn);\n\t\n\t if (settings.type == 'prompt' || settings.type == 'confirm') {\n\t\n\t wrapper.appendChild(cancelBtn);\n\t }\n\t\n\t wrapper.classList.add('cdx-notification-' + settings.type);\n\t wrapper.dataset.type = settings.type;\n\t\n\t notification = wrapper;\n\t type = settings.type;\n\t confirm = settings.confirm;\n\t cancel = settings.cancel;\n\t inputField = input;\n\t\n\t if (settings.type != 'prompt' && settings.type != 'confirm') {\n\t\n\t window.setTimeout(close, settings.time);\n\t }\n\t };\n\t\n\t function send() {\n\t\n\t editor.nodes.notifications.appendChild(notification);\n\t inputField.focus();\n\t\n\t editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\n\t\n\t window.setTimeout(function () {\n\t\n\t editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n\t }, 100);\n\t\n\t addToQueue({ type: type, close: close });\n\t };\n\t\n\t function close() {\n\t\n\t notification.remove();\n\t };\n\t\n\t if (constructorSettings) {\n\t\n\t create(constructorSettings);\n\t send();\n\t }\n\t\n\t return {\n\t create: create,\n\t send: send,\n\t close: close\n\t };\n\t };\n\t\n\t notifications.clear = function () {\n\t\n\t editor.nodes.notifications.innerHTML = '';\n\t queue = [];\n\t };\n\t\n\t return notifications;\n\t}({});\n\n/***/ },\n/* 16 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\t/**\n\t * Codex Editor Parser Module\n\t *\n\t * @author Codex Team\n\t * @version 1.1\n\t */\n\t\n\tmodule.exports = function (parser) {\n\t\n\t var editor = codex.editor;\n\t\n\t /** inserting text */\n\t parser.insertPastedContent = function (blockType, tag) {\n\t\n\t editor.content.insertBlock({\n\t type: blockType.type,\n\t block: blockType.render({\n\t text: tag.innerHTML\n\t })\n\t });\n\t };\n\t\n\t /**\n\t * Check DOM node for display style: separated block or child-view\n\t */\n\t parser.isFirstLevelBlock = function (node) {\n\t\n\t return node.nodeType == editor.core.nodeTypes.TAG && node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n\t };\n\t\n\t return parser;\n\t}({});\n\n/***/ },\n/* 17 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Sanitizer\n\t */\n\t\n\tmodule.exports = function (sanitizer) {\n\t\n\t var janitor = __webpack_require__(18);\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/* 18 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory) {\n\t if (true) {\n\t !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t } else if (typeof exports === 'object') {\n\t module.exports = factory();\n\t } else {\n\t root.HTMLJanitor = factory();\n\t }\n\t}(this, function () {\n\t\n\t /**\n\t * @param {Object} config.tags Dictionary of allowed tags.\n\t * @param {boolean} config.keepNestedBlockElements Default false.\n\t */\n\t function HTMLJanitor(config) {\n\t\n\t var tagDefinitions = config['tags'];\n\t var tags = Object.keys(tagDefinitions);\n\t\n\t var validConfigValues = tags\n\t .map(function(k) { return typeof tagDefinitions[k]; })\n\t .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; });\n\t\n\t if(!validConfigValues) {\n\t throw new Error(\"The configuration was invalid\");\n\t }\n\t\n\t this.config = config;\n\t }\n\t\n\t // TODO: not exhaustive?\n\t var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE'];\n\t function isBlockElement(node) {\n\t return blockElementNames.indexOf(node.nodeName) !== -1;\n\t }\n\t\n\t var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE'];\n\t function isInlineElement(node) {\n\t return inlineElementNames.indexOf(node.nodeName) !== -1;\n\t }\n\t\n\t HTMLJanitor.prototype.clean = function (html) {\n\t var sandbox = document.createElement('div');\n\t sandbox.innerHTML = html;\n\t\n\t this._sanitize(sandbox);\n\t\n\t return sandbox.innerHTML;\n\t };\n\t\n\t HTMLJanitor.prototype._sanitize = function (parentNode) {\n\t var treeWalker = createTreeWalker(parentNode);\n\t var node = treeWalker.firstChild();\n\t if (!node) { return; }\n\t\n\t do {\n\t // Ignore nodes that have already been sanitized\n\t if (node._sanitized) {\n\t continue;\n\t }\n\t\n\t if (node.nodeType === Node.TEXT_NODE) {\n\t // If this text node is just whitespace and the previous or next element\n\t // sibling is a block element, remove it\n\t // N.B.: This heuristic could change. Very specific to a bug with\n\t // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output\n\t // FIXME: make this an option?\n\t if (node.data.trim() === ''\n\t && ((node.previousElementSibling && isBlockElement(node.previousElementSibling))\n\t || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) {\n\t parentNode.removeChild(node);\n\t this._sanitize(parentNode);\n\t break;\n\t } else {\n\t continue;\n\t }\n\t }\n\t\n\t // Remove all comments\n\t if (node.nodeType === Node.COMMENT_NODE) {\n\t parentNode.removeChild(node);\n\t this._sanitize(parentNode);\n\t break;\n\t }\n\t\n\t var isInline = isInlineElement(node);\n\t var containsBlockElement;\n\t if (isInline) {\n\t containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement);\n\t }\n\t\n\t // Block elements should not be nested (e.g.

  • ...); if\n\t // they are, we want to unwrap the inner block element.\n\t var isNotTopContainer = !! parentNode.parentNode;\n\t var isNestedBlockElement =\n\t isBlockElement(parentNode) &&\n\t isBlockElement(node) &&\n\t isNotTopContainer;\n\t\n\t var nodeName = node.nodeName.toLowerCase();\n\t\n\t var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\t\n\t var isInvalid = isInline && containsBlockElement;\n\t\n\t // Drop tag entirely according to the whitelist *and* if the markup\n\t // is invalid.\n\t if (isInvalid || shouldRejectNode(node, allowedAttrs)\n\t || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n\t // Do not keep the inner text of SCRIPT/STYLE elements.\n\t if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n\t while (node.childNodes.length > 0) {\n\t parentNode.insertBefore(node.childNodes[0], node);\n\t }\n\t }\n\t parentNode.removeChild(node);\n\t\n\t this._sanitize(parentNode);\n\t break;\n\t }\n\t\n\t // Sanitize attributes\n\t for (var a = 0; a < node.attributes.length; a += 1) {\n\t var attr = node.attributes[a];\n\t\n\t if (shouldRejectAttr(attr, allowedAttrs, node)) {\n\t node.removeAttribute(attr.name);\n\t // Shift the array to continue looping.\n\t a = a - 1;\n\t }\n\t }\n\t\n\t // Sanitize children\n\t this._sanitize(node);\n\t\n\t // Mark node as sanitized so it's ignored in future runs\n\t node._sanitized = true;\n\t } while ((node = treeWalker.nextSibling()));\n\t };\n\t\n\t function createTreeWalker(node) {\n\t return document.createTreeWalker(node,\n\t NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n\t null, false);\n\t }\n\t\n\t function getAllowedAttrs(config, nodeName, node){\n\t if (typeof config.tags[nodeName] === 'function') {\n\t return config.tags[nodeName](node);\n\t } else {\n\t return config.tags[nodeName];\n\t }\n\t }\n\t\n\t function shouldRejectNode(node, allowedAttrs){\n\t if (typeof allowedAttrs === 'undefined') {\n\t return true;\n\t } else if (typeof allowedAttrs === 'boolean') {\n\t return !allowedAttrs;\n\t }\n\t\n\t return false;\n\t }\n\t\n\t function shouldRejectAttr(attr, allowedAttrs, node){\n\t var attrName = attr.name.toLowerCase();\n\t\n\t if (allowedAttrs === true){\n\t return false;\n\t } else if (typeof allowedAttrs[attrName] === 'function'){\n\t return !allowedAttrs[attrName](attr.value, node);\n\t } else if (typeof allowedAttrs[attrName] === 'undefined'){\n\t return true;\n\t } else if (allowedAttrs[attrName] === false) {\n\t return true;\n\t } else if (typeof allowedAttrs[attrName] === 'string') {\n\t return (allowedAttrs[attrName] !== attr.value);\n\t }\n\t\n\t return false;\n\t }\n\t\n\t return HTMLJanitor;\n\t\n\t}));\n\n\n/***/ },\n/* 19 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Anchors module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (anchors) {\n\t\n\t var editor = codex.editor;\n\t\n\t anchors.input = null;\n\t anchors.currentNode = null;\n\t\n\t anchors.settingsOpened = function (currentBlock) {\n\t\n\t anchors.currentNode = currentBlock;\n\t anchors.input.value = anchors.currentNode.dataset.anchor || '';\n\t };\n\t\n\t anchors.anchorChanged = function (e) {\n\t\n\t var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);\n\t\n\t anchors.currentNode.dataset.anchor = newAnchor;\n\t\n\t if (newAnchor.trim() !== '') {\n\t\n\t anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t } else {\n\t\n\t anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t };\n\t\n\t anchors.keyDownOnAnchorInput = function (e) {\n\t\n\t if (e.keyCode == editor.core.keys.ENTER) {\n\t\n\t e.preventDefault();\n\t e.stopPropagation();\n\t\n\t e.target.blur();\n\t editor.toolbar.settings.close();\n\t }\n\t };\n\t\n\t anchors.keyUpOnAnchorInput = function (e) {\n\t\n\t if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {\n\t\n\t e.stopPropagation();\n\t }\n\t };\n\t\n\t anchors.rusToTranslit = function (string) {\n\t\n\t var ru = ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'],\n\t en = ['A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya'];\n\t\n\t for (var i = 0; i < ru.length; i++) {\n\t\n\t string = string.split(ru[i]).join(en[i]);\n\t string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());\n\t }\n\t\n\t string = string.replace(/[^0-9a-zA-Z_]+/g, '-');\n\t\n\t return string;\n\t };\n\t\n\t return anchors;\n\t}({});\n\n/***/ },\n/* 20 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\t/**\n\t * Codex Editor Listeners module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\t/**\n\t * Module-decorator for event listeners assignment\n\t */\n\tmodule.exports = function (listeners) {\n\t\n\t var allListeners = [];\n\t\n\t /**\n\t * Search methods\n\t *\n\t * byElement, byType and byHandler returns array of suitable listeners\n\t * one and all takes element, eventType, and handler and returns first (all) suitable listener\n\t *\n\t */\n\t listeners.search = function () {\n\t\n\t var byElement = function byElement(element, context) {\n\t\n\t var listenersOnElement = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.element === element) {\n\t\n\t listenersOnElement.push(listener);\n\t }\n\t }\n\t\n\t return listenersOnElement;\n\t };\n\t\n\t var byType = function byType(eventType, context) {\n\t\n\t var listenersWithType = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.type === eventType) {\n\t\n\t listenersWithType.push(listener);\n\t }\n\t }\n\t\n\t return listenersWithType;\n\t };\n\t\n\t var byHandler = function byHandler(handler, context) {\n\t\n\t var listenersWithHandler = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.handler === handler) {\n\t\n\t listenersWithHandler.push(listener);\n\t }\n\t }\n\t\n\t return listenersWithHandler;\n\t };\n\t\n\t var one = function one(element, eventType, handler) {\n\t\n\t var result = allListeners;\n\t\n\t if (element) result = byElement(element, result);\n\t\n\t if (eventType) result = byType(eventType, result);\n\t\n\t if (handler) result = byHandler(handler, result);\n\t\n\t return result[0];\n\t };\n\t\n\t var all = function all(element, eventType, handler) {\n\t\n\t var result = allListeners;\n\t\n\t if (element) result = byElement(element, result);\n\t\n\t if (eventType) result = byType(eventType, result);\n\t\n\t if (handler) result = byHandler(handler, result);\n\t\n\t return result;\n\t };\n\t\n\t return {\n\t byElement: byElement,\n\t byType: byType,\n\t byHandler: byHandler,\n\t one: one,\n\t all: all\n\t };\n\t }();\n\t\n\t listeners.add = function (element, eventType, handler, isCapture) {\n\t\n\t element.addEventListener(eventType, handler, isCapture);\n\t\n\t var data = {\n\t element: element,\n\t type: eventType,\n\t handler: handler\n\t };\n\t\n\t var alreadyAddedListener = listeners.search.one(element, eventType, handler);\n\t\n\t if (!alreadyAddedListener) {\n\t\n\t allListeners.push(data);\n\t }\n\t };\n\t\n\t listeners.remove = function (element, eventType, handler) {\n\t\n\t element.removeEventListener(eventType, handler);\n\t\n\t var existingListeners = listeners.search.all(element, eventType, handler);\n\t\n\t for (var i = 0; i < existingListeners.length; i++) {\n\t\n\t var index = allListeners.indexOf(existingListeners[i]);\n\t\n\t if (index > 0) {\n\t\n\t allListeners.splice(index, 1);\n\t }\n\t }\n\t };\n\t\n\t listeners.removeAll = function () {\n\t\n\t allListeners.map(function (current) {\n\t\n\t listeners.remove(current.element, current.type, current.handler);\n\t });\n\t };\n\t\n\t listeners.get = function (element, eventType, handler) {\n\t\n\t return listeners.search.all(element, eventType, handler);\n\t };\n\t\n\t return listeners;\n\t}({});\n\n/***/ },\n/* 21 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\t\n\t/**\n\t * Codex Editor Destroyer module\n\t *\n\t * @auhor Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (destroyer) {\n\t\n\t var editor = codex.editor;\n\t\n\t destroyer.removeNodes = function () {\n\t\n\t editor.nodes.wrapper.remove();\n\t editor.nodes.notifications.remove();\n\t };\n\t\n\t destroyer.destroyPlugins = function () {\n\t\n\t for (var tool in editor.tools) {\n\t\n\t if (typeof editor.tools[tool].destroy === 'function') {\n\t\n\t editor.tools[tool].destroy();\n\t }\n\t }\n\t };\n\t\n\t destroyer.destroyScripts = function () {\n\t\n\t var scripts = document.getElementsByTagName('SCRIPT');\n\t\n\t for (var i = 0; i < scripts.length; i++) {\n\t\n\t if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n\t\n\t scripts[i].remove();\n\t i--;\n\t }\n\t }\n\t };\n\t\n\t /**\n\t * Delete editor data from webpage.\n\t * You should send settings argument with boolean flags:\n\t * @param settings.ui- remove redactor event listeners and DOM nodes\n\t * @param settings.scripts - remove redactor scripts from DOM\n\t * @param settings.plugins - remove plugin's objects\n\t * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\n\t * }\n\t *\n\t */\n\t destroyer.destroy = function (settings) {\n\t\n\t if (!settings || (typeof settings === 'undefined' ? 'undefined' : _typeof(settings)) !== 'object') {\n\t\n\t return;\n\t }\n\t\n\t if (settings.ui) {\n\t\n\t destroyer.removeNodes();\n\t editor.listeners.removeAll();\n\t }\n\t\n\t if (settings.scripts) {\n\t\n\t destroyer.destroyScripts();\n\t }\n\t\n\t if (settings.plugins) {\n\t\n\t destroyer.destroyPlugins();\n\t }\n\t\n\t if (settings.ui && settings.scripts && settings.core) {\n\t\n\t delete codex.editor;\n\t }\n\t };\n\t\n\t return destroyer;\n\t}({});\n\n/***/ },\n/* 22 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Paste module\n\t *\n\t * @author Codex Team\n\t * @version 1.1.1\n\t */\n\t\n\tmodule.exports = function (paste) {\n\t\n\t var editor = codex.editor;\n\t\n\t var patterns = [];\n\t\n\t paste.prepare = function () {\n\t\n\t var tools = editor.tools;\n\t\n\t for (var tool in tools) {\n\t\n\t if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n\t\n\t continue;\n\t }\n\t\n\t tools[tool].renderOnPastePatterns.map(function (pattern) {\n\t\n\t patterns.push(pattern);\n\t });\n\t }\n\t\n\t return Promise.resolve();\n\t };\n\t\n\t /**\n\t * Saves data\n\t * @param event\n\t */\n\t paste.pasted = function (event) {\n\t\n\t var clipBoardData = event.clipboardData || window.clipboardData,\n\t content = clipBoardData.getData('Text');\n\t\n\t var result = analize(content);\n\t\n\t if (result) {\n\t\n\t event.preventDefault();\n\t event.stopImmediatePropagation();\n\t }\n\t\n\t return result;\n\t };\n\t\n\t /**\n\t * Analizes pated string and calls necessary method\n\t */\n\t\n\t var analize = function analize(string) {\n\t\n\t var result = false,\n\t content = editor.content.currentNode,\n\t plugin = content.dataset.tool;\n\t\n\t patterns.map(function (pattern) {\n\t\n\t var execArray = pattern.regex.exec(string),\n\t match = execArray && execArray[0];\n\t\n\t if (match && match === string.trim()) {\n\t\n\t /** current block is not empty */\n\t if (content.textContent.trim() && plugin == editor.settings.initialBlockPlugin) {\n\t\n\t pasteToNewBlock_();\n\t }\n\t\n\t pattern.callback(string, pattern);\n\t result = true;\n\t }\n\t });\n\t\n\t return result;\n\t };\n\t\n\t var pasteToNewBlock_ = function pasteToNewBlock_() {\n\t\n\t /** Create new initial block */\n\t editor.content.insertBlock({\n\t\n\t type: editor.settings.initialBlockPlugin,\n\t block: editor.tools[editor.settings.initialBlockPlugin].render({\n\t text: ''\n\t })\n\t\n\t }, false);\n\t };\n\t\n\t return paste;\n\t}({});\n\n/***/ }\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// codex-editor.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap c51dcadf3df37e83f076","/**\n *\n * Codex Editor\n *\n * @author Codex Team\n */\n\nmodule.exports = (function (editor) {\n\n 'use strict';\n\n editor.version = VERSION;\n editor.scriptPrefix = 'cdx-script-';\n\n var init = function () {\n\n editor.core = require('./modules/core');\n editor.tools = require('./modules/tools');\n editor.ui = require('./modules/ui');\n editor.transport = require('./modules/transport');\n editor.renderer = require('./modules/renderer');\n editor.saver = require('./modules/saver');\n editor.content = require('./modules/content');\n editor.toolbar = require('./modules/toolbar/toolbar');\n editor.callback = require('./modules/callbacks');\n editor.draw = require('./modules/draw');\n editor.caret = require('./modules/caret');\n editor.notifications = require('./modules/notifications');\n editor.parser = require('./modules/parser');\n editor.sanitizer = require('./modules/sanitizer');\n editor.anchors = require('./modules/anchors');\n editor.listeners = require('./modules/listeners');\n editor.destroyer = require('./modules/destroyer');\n editor.paste = require('./modules/paste');\n\n };\n\n /**\n * @public\n *\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.tools.prepare)\n .then(editor.paste.prepare)\n .then(editor.transport.prepare)\n .then(editor.renderer.makeBlocksFromData)\n .then(editor.ui.saveInputs)\n .catch(function (error) {\n\n editor.core.log('Initialization failed with error: %o', 'warn', error);\n\n });\n\n };\n\n return editor;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./codex.js","/**\n * Codex Editor Core\n *\n * @author Codex Team\n * @version 1.1.2\n */\n\nmodule.exports = (function (core) {\n\n let editor = codex.editor;\n\n /**\n * @public\n *\n * Editor preparing method\n * @return Promise\n */\n core.prepare = function (userSettings) {\n\n return new Promise(function (resolve, reject) {\n\n if ( userSettings ) {\n\n editor.settings.tools = userSettings.tools || editor.settings.tools;\n\n }\n\n if (userSettings.data) {\n\n editor.state.blocks = userSettings.data;\n\n }\n\n if (userSettings.initialBlockPlugin) {\n\n editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\n\n }\n\n if (userSettings.uploadImagesUrl) {\n\n editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;\n\n }\n\n editor.hideToolbar = userSettings.hideToolbar;\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 * Checks passed object for emptiness\n * @require ES5 - Object.keys\n * @param {object}\n */\n core.isEmpty = function ( obj ) {\n\n return Object.keys(obj).length === 0;\n\n };\n\n /**\n * Native Ajax\n */\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 let script;\n\n /** Script is already loaded */\n if ( !instanceName ) {\n\n reject('Instance name is missed');\n\n } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) {\n\n resolve(scriptPath);\n\n }\n\n script = document.createElement('SCRIPT');\n script.async = true;\n script.defer = true;\n script.id = editor.scriptPrefix + instanceName;\n\n script.onload = function () {\n\n resolve(scriptPath);\n\n };\n\n script.onerror = function () {\n\n reject(scriptPath);\n\n };\n\n script.src = scriptPath;\n document.head.appendChild(script);\n\n });\n\n };\n\n return core;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/core.js","/**\n* Module working with plugins\n*/\nmodule.exports = (function () {\n\n let editor = codex.editor;\n\n /**\n * Initialize plugins before using\n * Ex. Load scripts or call some internal methods\n * @return Promise\n */\n function prepare() {\n\n return new Promise(function (resolve_, reject_) {\n\n Promise.resolve()\n\n /**\n * Compose a sequence of plugins that requires preparation\n */\n .then(function () {\n\n let pluginsRequiresPreparation = [],\n allPlugins = editor.tools;\n\n for ( let pluginName in allPlugins ) {\n\n let plugin = allPlugins[pluginName];\n\n if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {\n\n continue;\n\n }\n\n pluginsRequiresPreparation.push(plugin);\n\n }\n\n /**\n * If no one passed plugins requires preparation, finish prepare() and go ahead\n */\n if (!pluginsRequiresPreparation.length) {\n\n resolve_();\n\n }\n\n return pluginsRequiresPreparation;\n\n })\n\n /** Wait plugins while they prepares */\n .then(waitAllPluginsPreparation_)\n\n .then(function () {\n\n editor.core.log('Plugins loaded', 'info');\n resolve_();\n\n }).catch(function (error) {\n\n reject_(error);\n\n });\n\n });\n\n }\n\n /**\n * @param {array} plugins - list of tools that requires preparation\n * @return {Promise} resolved while all plugins will be ready or failed\n */\n function waitAllPluginsPreparation_(plugins) {\n\n /**\n * @calls allPluginsProcessed__ when all plugins prepared or failed\n */\n return new Promise (function (allPluginsProcessed__) {\n\n /**\n * pluck each element from queue\n * First, send resolved Promise as previous value\n * Each plugins \"prepare\" method returns a Promise, that's why\n * reduce current element will not be able to continue while can't get\n * a resolved Promise\n *\n * If last plugin is \"prepared\" then go to the next stage of initialization\n */\n plugins.reduce(function (previousValue, plugin, iteration) {\n\n return previousValue.then(function () {\n\n /**\n * Wait till plugins prepared\n * @calls pluginIsReady__ when plugin is ready or failed\n */\n return new Promise ( function (pluginIsReady__) {\n\n callPluginsPrepareMethod_( plugin )\n\n .then( pluginIsReady__ )\n .then( function () {\n\n plugin.available = true;\n\n })\n\n .catch(function (error) {\n\n editor.core.log(`Plugin «${plugin.type}» was not loaded. Preparation failed because %o`, 'warn', error);\n plugin.available = false;\n plugin.loadingMessage = error;\n\n /** Go ahead even some plugin has problems */\n pluginIsReady__();\n\n })\n\n .then(function () {\n\n /** If last plugin has problems then just ignore and continue */\n if (iteration == plugins.length - 1) {\n\n allPluginsProcessed__();\n\n }\n\n });\n\n });\n\n });\n\n }, Promise.resolve() );\n\n });\n\n }\n\n var callPluginsPrepareMethod_ = function (plugin) {\n\n return plugin.prepare( plugin.config || {} );\n\n };\n\n return {\n prepare: prepare\n };\n\n}());\n\n\n// WEBPACK FOOTER //\n// ./modules/tools.js","/**\n * Codex Editor UI module\n *\n * @author Codex Team\n * @version 1.1.3\n */\n\nmodule.exports = (function (ui) {\n\n let editor = codex.editor;\n\n /**\n * Basic editor classnames\n */\n ui.className = {\n\n /**\n * @const {string} BLOCK_CLASSNAME - redactor blocks name\n */\n BLOCK_CLASSNAME : 'ce-block',\n\n /**\n * @const {String} wrapper for plugins content\n */\n BLOCK_CONTENT : 'ce-block__content',\n\n /**\n * @const {String} BLOCK_STRETCHED - makes block stretched\n */\n BLOCK_STRETCHED : 'ce-block--stretched',\n\n /**\n * @const {String} BLOCK_HIGHLIGHTED - adds background\n */\n BLOCK_HIGHLIGHTED : 'ce-block--focused',\n\n /**\n * @const {String} - highlights covered blocks\n */\n BLOCK_IN_FEED_MODE : 'ce-block--feed-mode',\n\n /**\n * @const {String} - Block with anchor\n */\n BLOCK_WITH_ANCHOR : 'ce-block--anchor',\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 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 editor.notifications.createHolder();\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 && tool.displayInToolbox) {\n\n editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\n continue;\n\n }\n\n if (typeof tool.render != 'function') {\n\n editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\n continue;\n\n }\n\n if (!tool.displayInToolbox) {\n\n continue;\n\n } else {\n\n /** if tools is for toolbox */\n toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\n\n editor.nodes.toolbox.appendChild(toolButton);\n\n editor.nodes.toolbarButtons[toolName] = toolButton;\n\n }\n\n }\n\n /**\n * 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 editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n\n /** All keydowns on Redactor zone */\n editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n\n /** All keydowns on Document */\n editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );\n\n /**\n * Mouse click to radactor\n */\n editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );\n\n /**\n * Clicks to the Plus button\n */\n editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n\n /**\n * Clicks to SETTINGS button in toolbar\n */\n editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );\n\n /**\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.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n\n }\n\n };\n\n ui.addBlockHandlers = function (block) {\n\n if (!block) return;\n\n /**\n * Block keydowns\n */\n editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n\n /**\n * Pasting content from another source\n * We have two type of sanitization\n * First - uses deep-first search algorithm to get sub nodes,\n * sanitizes whole Block_content and replaces cleared nodes\n * This method is deprecated\n * Method is used in editor.callback.blockPaste(event)\n *\n * Secont - uses Mutation observer.\n * Observer \"observe\" DOM changes and send changings to callback.\n * Callback gets changed node, not whole Block_content.\n * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n *\n * Method is used in editor.callback.blockPasteViaSanitize(event)\n *\n * @uses html-janitor\n * @example editor.callback.blockPasteViaSanitize(event), the second method.\n *\n */\n editor.listeners.add(block, 'paste', editor.callback.blockPasteCallback, false);\n\n editor.listeners.add(block, '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 editor.listeners.add(button, 'mousedown', function (event) {\n\n editor.toolbar.inline.toolClicked(event, type);\n\n }, false);\n\n };\n\n return ui;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/ui.js","/**\n *\n * Codex.Editor Transport Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (transport) {\n\n let editor = codex.editor;\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 editor.listeners.add(input, '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\nmodule.exports = (function (renderer) {\n\n let editor = codex.editor;\n\n /**\n * Asyncronously parses input JSON to redactor blocks\n */\n renderer.makeBlocksFromData = function () {\n\n /**\n * If redactor is empty, add first paragraph to start writing\n */\n if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {\n\n editor.ui.addInitialBlock();\n return;\n\n }\n\n Promise.resolve()\n\n /** First, get JSON from state */\n .then(function () {\n\n return editor.state.blocks;\n\n })\n\n /** Then, start to iterate they */\n .then(editor.renderer.appendBlocks)\n\n /** Write log if something goes wrong */\n .catch(function (error) {\n\n editor.core.log('Error while parsing JSON: %o', 'error', error);\n\n });\n\n };\n\n /**\n * Parses JSON to blocks\n * @param {object} data\n * @return Primise -> nodeList\n */\n renderer.appendBlocks = function (data) {\n\n var blocks = data.items;\n\n /**\n * Sequence of one-by-one blocks appending\n * Uses to save blocks order after async-handler\n */\n var nodeSequence = Promise.resolve();\n\n for (var index = 0; index < blocks.length ; index++ ) {\n\n /** Add node to sequence at specified index */\n editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\n\n }\n\n };\n\n /**\n * Append node at specified index\n */\n renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\n\n /** We need to append node to sequence */\n nodeSequence\n\n /** first, get node async-aware */\n .then(function () {\n\n return editor.renderer.getNodeAsync(blocks, index);\n\n })\n\n /**\n * second, compose editor-block from JSON object\n */\n .then(editor.renderer.createBlockFromData)\n\n /**\n * now insert block to redactor\n */\n .then(function (blockData) {\n\n /**\n * blockData has 'block', 'type' and 'stretched' information\n */\n editor.content.insertBlock(blockData);\n\n /** Pass created block to next step */\n return blockData.block;\n\n })\n\n /** Log if something wrong with node */\n .catch(function (error) {\n\n editor.core.log('Node skipped while parsing because %o', 'error', error);\n\n });\n\n };\n\n /**\n * Asynchronously returns block data from blocksList by index\n * @return Promise to node\n */\n renderer.getNodeAsync = function (blocksList, index) {\n\n return Promise.resolve().then(function () {\n\n return {\n tool : blocksList[index],\n position : index\n };\n\n });\n\n };\n\n /**\n * Creates editor block by JSON-data\n *\n * @uses render method of each plugin\n *\n * @param {Object} toolData.tool\n * { header : {\n * text: '',\n * type: 'H3', ...\n * }\n * }\n * @param {Number} toolData.position - index in input-blocks array\n * @return {Object} with type and Element\n */\n renderer.createBlockFromData = function ( toolData ) {\n\n /** New parser */\n var block,\n tool = toolData.tool,\n pluginName = tool.type,\n anchor = tool.anchor,\n cover = tool.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 if ( editor.tools[pluginName].available === false ) {\n\n block = editor.draw.unavailableBlock();\n\n block.innerHTML = editor.tools[pluginName].loadingMessage;\n\n /**\n * Saver will extract data from initial block data by position in array\n */\n block.dataset.inputPosition = toolData.position;\n\n } else {\n\n /** New Parser */\n block = editor.tools[pluginName].render(tool.data);\n\n }\n\n /** is first-level block stretched */\n var stretched = editor.tools[pluginName].isStretched || false;\n\n /** Retrun type and block */\n return {\n type : pluginName,\n block : block,\n stretched : stretched,\n cover : cover,\n anchor : anchor\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\nmodule.exports = (function (saver) {\n\n let editor = codex.editor;\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 anchor = block.dataset.anchor;\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,\n position,\n output,\n coverFlag = false;\n\n /** If plugin wasn't available then return data from cache */\n if ( editor.tools[pluginName].available === false ) {\n\n position = pluginsContent.dataset.inputPosition;\n\n savedData = codex.editor.state.blocks.items[position].data;\n coverFlag = codex.editor.state.blocks.items[position].cover;\n anchor = codex.editor.state.blocks.items[position].anchor;\n\n } else {\n\n savedData = editor.tools[pluginName].save(pluginsContent);\n coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\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 }\n\n output = {\n type : pluginName,\n anchor : anchor,\n data : savedData\n };\n\n /** Marks Blocks that will be in main page */\n output.cover = coverFlag;\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.12\n */\n\nmodule.exports = (function (content) {\n\n let editor = codex.editor;\n\n /**\n * Links to current active block\n * @type {null | Element}\n */\n content.currentNode = null;\n\n /**\n * clicked in redactor area\n * @type {null | Boolean}\n */\n content.editorAreaHightlighted = null;\n\n /**\n * 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 if (targetBlock.classList.contains(editor.ui.className.BLOCK_WITH_ANCHOR)) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\n }\n\n /**\n * Saving anchor\n */\n newBlock.dataset.anchor = targetBlock.dataset.anchor;\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 anchor = blockData.anchor,\n isStretched = blockData.stretched;\n\n var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);\n\n if (cover === true) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\n }\n\n if (anchor) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\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 tool = tool || editor.content.currentNode.dataset.tool;\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, anchor) {\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 newBlock.dataset.anchor = anchor || '';\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 /**\n * Finds closest Contenteditable parent from Element\n * @param {Element} node element looking from\n * @return {Element} node contenteditable\n */\n content.getEditableParent = function (node) {\n\n while (node && node.contentEditable != 'true') {\n\n node = node.parentNode;\n\n }\n\n return node;\n\n };\n\n return content;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/content.js","/**\n * Codex Editor toolbar module\n *\n * Contains:\n * - Inline toolbox\n * - Toolbox within plus button\n * - Settings section\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (toolbar) {\n\n let editor = codex.editor;\n\n toolbar.settings = require('./settings');\n toolbar.inline = require('./inline');\n toolbar.toolbox = require('./toolbox');\n\n /**\n * Margin between focused node and toolbar\n */\n toolbar.defaultToolbarHeight = 49;\n\n toolbar.defaultOffset = 34;\n\n toolbar.opened = false;\n\n toolbar.current = null;\n\n /**\n * @protected\n */\n toolbar.open = function () {\n\n if (editor.hideToolbar) {\n\n return;\n\n }\n\n 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\nmodule.exports = (function (settings) {\n\n let editor = codex.editor;\n\n settings.opened = false;\n\n settings.setting = null;\n settings.actions = null;\n\n 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 editor.anchors.settingsOpened(editor.content.currentNode);\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 anchorInput;\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 anchorInput = editor.toolbar.settings.makeAnchorInput();\n\n /**\n * Fill defaultSettings\n */\n\n /**\n * Input for anchor for block\n */\n editor.nodes.defaultSettings.appendChild(anchorInput);\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 : 'Вывести в ленте'\n };\n\n } else {\n\n data = {\n innerHTML : 'Не выводить в ленте'\n };\n\n }\n\n setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\n editor.listeners.add(setting, '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 settings.makeAnchorInput = function () {\n\n var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),\n hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),\n anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });\n\n editor.listeners.add(anchor, 'keydown', editor.anchors.keyDownOnAnchorInput );\n editor.listeners.add(anchor, 'keyup', editor.anchors.keyUpOnAnchorInput );\n editor.listeners.add(anchor, 'input', editor.anchors.anchorChanged );\n editor.listeners.add(anchor, 'blur', editor.anchors.anchorChanged );\n\n anchorWrapper.appendChild(hash);\n anchorWrapper.appendChild(anchor);\n\n editor.anchors.input = anchor;\n\n return anchorWrapper;\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 : '' }),\n actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\n confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }),\n cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' });\n\n editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\n\n editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\n\n editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\n\n actionWrapper.appendChild(confirmAction);\n actionWrapper.appendChild(cancelAction);\n\n removeBlockWrapper.appendChild(settingButton);\n removeBlockWrapper.appendChild(actionWrapper);\n\n /** Save setting */\n editor.toolbar.settings.setting = settingButton;\n editor.toolbar.settings.actions = actionWrapper;\n\n return removeBlockWrapper;\n\n };\n\n settings.removeButtonClicked = function () {\n\n var action = editor.toolbar.settings.actions;\n\n if (action.classList.contains('opened')) {\n\n editor.toolbar.settings.hideRemoveActions();\n\n } else {\n\n editor.toolbar.settings.showRemoveActions();\n\n }\n\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.close();\n\n };\n\n settings.cancelRemovingRequest = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n settings.confirmRemovingRequest = function () {\n\n var currentBlock = editor.content.currentNode,\n firstLevelBlocksCount;\n\n currentBlock.remove();\n\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\n /**\n * If all blocks are removed\n */\n if (firstLevelBlocksCount === 0) {\n\n /** update currentNode variable */\n editor.content.currentNode = null;\n\n /** Inserting new empty initial block */\n editor.ui.addInitialBlock();\n\n }\n\n editor.ui.saveInputs();\n\n editor.toolbar.close();\n\n };\n\n settings.showRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.add('opened');\n\n };\n\n settings.hideRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n return settings;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/settings.js","/**\n * Inline toolbar\n *\n * Contains from tools:\n * Bold, Italic, Underline and Anchor\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (inline) {\n\n let editor = codex.editor;\n\n inline.buttonsOpened = null;\n inline.actionsOpened = null;\n inline.wrappersOffset = null;\n\n /**\n * saving selection that need for execCommand for styling\n *\n */\n inline.storedSelection = null;\n\n /**\n * @protected\n *\n * Open inline toobar\n */\n inline.show = function () {\n\n var currentNode = editor.content.currentNode,\n tool = currentNode.dataset.tool,\n plugin;\n\n /**\n * tool allowed to open inline toolbar\n */\n plugin = editor.tools[tool];\n\n if (!plugin.showInlineToolbar)\n return;\n\n var selectedText = inline.getSelectionText(),\n toolbar = editor.nodes.inlineToolbar.wrapper;\n\n if (selectedText.length > 0) {\n\n /** Move toolbar and open */\n editor.toolbar.inline.move();\n\n /** Open inline toolbar */\n toolbar.classList.add('opened');\n\n /** show buttons of inline toolbar */\n editor.toolbar.inline.showButtons();\n\n }\n\n };\n\n /**\n * @protected\n *\n * Closes inline toolbar\n */\n inline.close = function () {\n\n var toolbar = editor.nodes.inlineToolbar.wrapper;\n\n toolbar.classList.remove('opened');\n\n };\n\n /**\n * @private\n *\n * Moving toolbar\n */\n inline.move = function () {\n\n if (!this.wrappersOffset) {\n\n this.wrappersOffset = this.getWrappersOffset();\n\n }\n\n var coords = this.getSelectionCoords(),\n defaultOffset = 0,\n toolbar = editor.nodes.inlineToolbar.wrapper,\n newCoordinateX,\n newCoordinateY;\n\n if (toolbar.offsetHeight === 0) {\n\n defaultOffset = 40;\n\n }\n\n newCoordinateX = coords.x - this.wrappersOffset.left;\n newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;\n\n toolbar.style.transform = `translate3D(${Math.floor(newCoordinateX)}px, ${Math.floor(newCoordinateY)}px, 0)`;\n\n /** Close everything */\n editor.toolbar.inline.closeButtons();\n editor.toolbar.inline.closeAction();\n\n };\n\n /**\n * @private\n *\n * Tool Clicked\n */\n\n inline.toolClicked = function (event, type) {\n\n /**\n * For simple tools we use default browser function\n * For more complicated tools, we should write our own behavior\n */\n switch (type) {\n case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break;\n default : editor.toolbar.inline.defaultToolAction(type); break;\n }\n\n /**\n * highlight buttons\n * after making some action\n */\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\n };\n\n /**\n * @private\n *\n * Saving wrappers offset in DOM\n */\n inline.getWrappersOffset = function () {\n\n var wrapper = editor.nodes.wrapper,\n offset = this.getOffset(wrapper);\n\n this.wrappersOffset = offset;\n return offset;\n\n };\n\n /**\n * @private\n *\n * Calculates offset of DOM element\n *\n * @param el\n * @returns {{top: number, left: number}}\n */\n inline.getOffset = function ( el ) {\n\n var _x = 0;\n var _y = 0;\n\n while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {\n\n _x += (el.offsetLeft + el.clientLeft);\n _y += (el.offsetTop + el.clientTop);\n el = el.offsetParent;\n\n }\n return { top: _y, left: _x };\n\n };\n\n /**\n * @private\n *\n * Calculates position of selected text\n * @returns {{x: number, y: number}}\n */\n inline.getSelectionCoords = function () {\n\n var sel = document.selection, range;\n var x = 0, y = 0;\n\n if (sel) {\n\n if (sel.type != 'Control') {\n\n range = sel.createRange();\n range.collapse(true);\n x = range.boundingLeft;\n y = range.boundingTop;\n\n }\n\n } else if (window.getSelection) {\n\n sel = window.getSelection();\n\n if (sel.rangeCount) {\n\n range = sel.getRangeAt(0).cloneRange();\n if (range.getClientRects) {\n\n range.collapse(true);\n var rect = range.getClientRects()[0];\n\n if (!rect) {\n\n return;\n\n }\n\n x = rect.left;\n y = rect.top;\n\n }\n\n }\n\n }\n return { x: x, y: y };\n\n };\n\n /**\n * @private\n *\n * Returns selected text as String\n * @returns {string}\n */\n inline.getSelectionText = function () {\n\n var selectedText = '';\n\n // all modern browsers and IE9+\n if (window.getSelection) {\n\n selectedText = window.getSelection().toString();\n\n }\n\n return selectedText;\n\n };\n\n /** Opens buttons block */\n inline.showButtons = function () {\n\n var buttons = editor.nodes.inlineToolbar.buttons;\n\n buttons.classList.add('opened');\n\n editor.toolbar.inline.buttonsOpened = true;\n\n /** highlight buttons */\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\n };\n\n /** Makes buttons disappear */\n inline.closeButtons = function () {\n\n var buttons = editor.nodes.inlineToolbar.buttons;\n\n buttons.classList.remove('opened');\n\n editor.toolbar.inline.buttonsOpened = false;\n\n };\n\n /** Open buttons defined action if exist */\n inline.showActions = function () {\n\n var action = editor.nodes.inlineToolbar.actions;\n\n action.classList.add('opened');\n\n editor.toolbar.inline.actionsOpened = true;\n\n };\n\n /** Close actions block */\n inline.closeAction = function () {\n\n var action = editor.nodes.inlineToolbar.actions;\n\n action.innerHTML = '';\n action.classList.remove('opened');\n editor.toolbar.inline.actionsOpened = false;\n\n };\n\n\n /**\n * Callback for keydowns in inline toolbar \"Insert link...\" input\n */\n let inlineToolbarAnchorInputKeydown_ = function (event) {\n\n if (event.keyCode != editor.core.keys.ENTER) {\n\n return;\n\n }\n\n let editable = editor.content.currentNode,\n storedSelection = editor.toolbar.inline.storedSelection;\n\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\n editor.toolbar.inline.setAnchor(this.value);\n\n /**\n * Preventing events that will be able to happen\n */\n event.preventDefault();\n event.stopImmediatePropagation();\n\n editor.toolbar.inline.clearRange();\n\n };\n\n /** Action for link creation or for setting anchor */\n inline.createLinkAction = function (event) {\n\n var isActive = this.isLinkActive();\n\n var editable = editor.content.currentNode,\n storedSelection = editor.toolbar.inline.saveSelection(editable);\n\n /** Save globally selection */\n editor.toolbar.inline.storedSelection = storedSelection;\n\n if (isActive) {\n\n\n /**\n * Changing stored selection. if we want to remove anchor from word\n * we should remove anchor from whole word, not only selected part.\n * The solution is than we get the length of current link\n * Change start position to - end of selection minus length of anchor\n */\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\n editor.toolbar.inline.defaultToolAction('unlink');\n\n } else {\n\n /** Create input and close buttons */\n var action = editor.draw.inputForLink();\n\n editor.nodes.inlineToolbar.actions.appendChild(action);\n\n editor.toolbar.inline.closeButtons();\n editor.toolbar.inline.showActions();\n\n /**\n * focus to input\n * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\n * Prevents event after showing input and when we need to focus an input which is in unexisted form\n */\n action.focus();\n event.preventDefault();\n\n /** Callback to link action */\n editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);\n\n }\n\n };\n\n inline.isLinkActive = function () {\n\n var isActive = false;\n\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\n\n var dataType = tool.dataset.type;\n\n if (dataType == 'link' && tool.classList.contains('hightlighted')) {\n\n isActive = true;\n\n }\n\n });\n\n return isActive;\n\n };\n\n /** default action behavior of tool */\n inline.defaultToolAction = function (type) {\n\n document.execCommand(type, false, null);\n\n };\n\n /**\n * @private\n *\n * Sets URL\n *\n * @param {String} url - URL\n */\n inline.setAnchor = function (url) {\n\n document.execCommand('createLink', false, url);\n\n /** Close after URL inserting */\n editor.toolbar.inline.closeAction();\n\n };\n\n /**\n * @private\n *\n * Saves selection\n */\n inline.saveSelection = function (containerEl) {\n\n var range = window.getSelection().getRangeAt(0),\n preSelectionRange = range.cloneRange(),\n start;\n\n preSelectionRange.selectNodeContents(containerEl);\n preSelectionRange.setEnd(range.startContainer, range.startOffset);\n\n start = preSelectionRange.toString().length;\n\n return {\n start: start,\n end: start + range.toString().length\n };\n\n };\n\n /**\n * @private\n *\n * Sets to previous selection (Range)\n *\n * @param {Element} containerEl - editable element where we restore range\n * @param {Object} savedSel - range basic information to restore\n */\n inline.restoreSelection = function (containerEl, savedSel) {\n\n var range = document.createRange(),\n charIndex = 0;\n\n range.setStart(containerEl, 0);\n range.collapse(true);\n\n var nodeStack = [ containerEl ],\n node,\n foundStart = false,\n stop = false,\n nextCharIndex;\n\n while (!stop && (node = nodeStack.pop())) {\n\n if (node.nodeType == 3) {\n\n nextCharIndex = charIndex + node.length;\n\n if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\n\n range.setStart(node, savedSel.start - charIndex);\n foundStart = true;\n\n }\n if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\n\n range.setEnd(node, savedSel.end - charIndex);\n stop = true;\n\n }\n charIndex = nextCharIndex;\n\n } else {\n\n var i = node.childNodes.length;\n\n while (i--) {\n\n nodeStack.push(node.childNodes[i]);\n\n }\n\n }\n\n }\n\n var sel = window.getSelection();\n\n sel.removeAllRanges();\n sel.addRange(range);\n\n };\n\n /**\n * @private\n *\n * Removes all ranges from window selection\n */\n inline.clearRange = function () {\n\n var selection = window.getSelection();\n\n selection.removeAllRanges();\n\n };\n\n /**\n * @private\n *\n * sets or removes hightlight\n */\n inline.hightlight = function (tool) {\n\n var dataType = tool.dataset.type;\n\n if (document.queryCommandState(dataType)) {\n\n editor.toolbar.inline.setButtonHighlighted(tool);\n\n } else {\n\n editor.toolbar.inline.removeButtonsHighLight(tool);\n\n }\n\n /**\n *\n * hightlight for anchors\n */\n var selection = window.getSelection(),\n tag = selection.anchorNode.parentNode;\n\n if (tag.tagName == 'A' && dataType == 'link') {\n\n editor.toolbar.inline.setButtonHighlighted(tool);\n\n }\n\n };\n\n /**\n * @private\n *\n * Mark button if text is already executed\n */\n inline.setButtonHighlighted = function (button) {\n\n button.classList.add('hightlighted');\n\n /** At link tool we also change icon */\n if (button.dataset.type == 'link') {\n\n var icon = button.childNodes[0];\n\n icon.classList.remove('ce-icon-link');\n icon.classList.add('ce-icon-unlink');\n\n }\n\n };\n\n /**\n * @private\n *\n * Removes hightlight\n */\n inline.removeButtonsHighLight = function (button) {\n\n button.classList.remove('hightlighted');\n\n /** At link tool we also change icon */\n if (button.dataset.type == 'link') {\n\n var icon = button.childNodes[0];\n\n icon.classList.remove('ce-icon-unlink');\n icon.classList.add('ce-icon-link');\n\n }\n\n };\n\n\n return inline;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/inline.js","/**\n * Codex Editor toolbox\n *\n * All tools be able to appended here\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (toolbox) {\n\n let editor = codex.editor;\n\n toolbox.opened = false;\n\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 */\n\nmodule.exports = (function (callbacks) {\n\n let editor = codex.editor;\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 var blockIsEmpty = !editor.content.currentNode.textContent.trim();\n\n if (!blockIsEmpty) {\n\n return;\n\n }\n\n if ( !editor.toolbar.opened ) {\n\n editor.toolbar.open();\n\n }\n\n if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\n editor.toolbar.toolbox.open();\n\n } else {\n\n editor.toolbar.toolbox.leaf();\n\n }\n\n 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

    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 if (!inputIsEmpty) {\n\n /** Mark current block */\n editor.content.markBlock();\n\n }\n\n if ( isInitialType && inputIsEmpty ) {\n\n /** Show plus button */\n editor.toolbar.showPlusButton();\n\n }\n\n\n };\n\n /**\n * This method allows to define, is caret in contenteditable element or not.\n * 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 var editableParent = editor.content.getEditableParent(event.target),\n firstLevelBlock = editor.content.getFirstLevelBlock(event.target);\n\n /** Allow paste when event target placed in Editable element */\n if (!editableParent) {\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 if (editor.tools[firstLevelBlock.dataset.tool].allowRenderOnPaste) {\n\n if (editor.paste.pasted(event)) return;\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 * @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 = '';\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 = '';\n\n return toggler;\n\n };\n\n /**\n * Redactor tools wrapper\n */\n\n draw.toolbox = function () {\n\n var wrapper = document.createElement('div');\n\n wrapper.className = 'ce-toolbar__tools';\n\n return wrapper;\n\n };\n\n /**\n * @protected\n *\n * Draws tool buttons for toolbox\n *\n * @param {String} type\n * @param {String} classname\n * @returns {Element}\n */\n draw.toolbarButton = function (type, classname) {\n\n var button = document.createElement('li'),\n toolIcon = document.createElement('i'),\n toolTitle = document.createElement('span');\n\n button.dataset.type = type;\n button.setAttribute('title', type);\n\n toolIcon.classList.add(classname);\n toolTitle.classList.add('ce_toolbar_tools--title');\n\n\n button.appendChild(toolIcon);\n button.appendChild(toolTitle);\n\n return button;\n\n };\n\n /**\n * @protected\n *\n * Draws tools for inline toolbar\n *\n * @param {String} type\n * @param {String} classname\n */\n draw.toolbarButtonInline = function (type, classname) {\n\n var button = document.createElement('BUTTON'),\n toolIcon = document.createElement('I');\n\n button.type = 'button';\n button.dataset.type = type;\n toolIcon.classList.add(classname);\n\n button.appendChild(toolIcon);\n\n return button;\n\n };\n\n /**\n * Redactor block\n */\n draw.block = function (tagName, content) {\n\n var node = document.createElement(tagName);\n\n node.innerHTML = content || '';\n\n return node;\n\n };\n\n /**\n * Creates Node with passed tagName and className\n * @param {string} tagName\n * @param {string} className\n * @param {object} properties - allow to assign properties\n */\n draw.node = function ( tagName, className, properties ) {\n\n var el = document.createElement( tagName );\n\n if ( className ) el.className = className;\n\n if ( properties ) {\n\n for (var name in properties) {\n\n el[name] = properties[name];\n\n }\n\n }\n\n return el;\n\n };\n\n /**\n * Unavailable plugin block\n */\n draw.unavailableBlock = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.classList.add('cdx-unavailable-block');\n\n return wrapper;\n\n };\n\n return draw;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/draw.js","/**\n * Codex Editor Caret Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (caret) {\n\n let editor = codex.editor;\n\n /**\n * @var {int} InputIndex - editable element in DOM\n */\n caret.inputIndex = null;\n\n /**\n * @var {int} offset - caret position in a text node.\n */\n caret.offset = null;\n\n /**\n * @var {int} focusedNodeIndex - we get index of child node from first-level block\n */\n caret.focusedNodeIndex = null;\n\n /**\n * Creates Document Range and sets caret to the element.\n * @protected\n * @uses caret.save — if you need to save caret position\n * @param {Element} el - Changed Node.\n */\n caret.set = function ( el, index, offset) {\n\n offset = offset || caret.offset || 0;\n index = index || caret.focusedNodeIndex || 0;\n\n var childs = el.childNodes,\n nodeToSet;\n\n if ( childs.length === 0 ) {\n\n nodeToSet = el;\n\n } else {\n\n nodeToSet = childs[index];\n\n }\n\n /** If Element is INPUT */\n if (el.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 */\n\nmodule.exports = (function (notifications) {\n\n let editor = codex.editor;\n\n var queue = [];\n\n var addToQueue = function (settings) {\n\n queue.push(settings);\n\n var index = 0;\n\n while ( index < queue.length && queue.length > 5) {\n\n if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n\n index++;\n continue;\n\n }\n\n queue[index].close();\n queue.splice(index, 1);\n\n }\n\n };\n\n notifications.createHolder = function () {\n\n var holder = editor.draw.node('DIV', 'cdx-notifications-block');\n\n editor.nodes.notifications = document.body.appendChild(holder);\n\n return holder;\n\n };\n\n\n /**\n * Error notificator. Shows block with message\n * @protected\n */\n notifications.errorThrown = function (errorMsg, event) {\n\n editor.notifications.notification({message: 'This action is not available currently', type: event.type});\n\n };\n\n /**\n *\n * Appends notification\n *\n * settings = {\n * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\n * message - notification message\n * okMsg - confirm button text (default - 'Ok')\n * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\n * confirm - function-handler for ok button click\n * cancel - function-handler for cancel button click. Only for confirm and prompt types\n * time - time (in seconds) after which notification will close (default - 10s)\n * }\n *\n * @param settings\n */\n notifications.notification = function (constructorSettings) {\n\n /** Private vars and methods */\n var notification = null,\n cancel = null,\n type = null,\n confirm = null,\n inputField = null;\n\n var confirmHandler = function () {\n\n close();\n\n if (typeof confirm !== 'function' ) {\n\n return;\n\n }\n\n if (type == 'prompt') {\n\n confirm(inputField.value);\n return;\n\n }\n\n confirm();\n\n };\n\n var cancelHandler = function () {\n\n close();\n\n if (typeof cancel !== 'function' ) {\n\n return;\n\n }\n\n cancel();\n\n };\n\n\n /** Public methods */\n function create(settings) {\n\n if (!(settings && settings.message)) {\n\n editor.core.log('Can\\'t create notification. Message is missed');\n return;\n\n }\n\n settings.type = settings.type || 'alert';\n settings.time = settings.time*1000 || 10000;\n\n var wrapper = editor.draw.node('DIV', 'cdx-notification'),\n message = editor.draw.node('DIV', 'cdx-notification__message'),\n input = editor.draw.node('INPUT', 'cdx-notification__input'),\n okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\n cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\n\n message.textContent = settings.message;\n okBtn.textContent = settings.okMsg || 'ОК';\n cancelBtn.textContent = settings.cancelMsg || 'Отмена';\n\n editor.listeners.add(okBtn, 'click', confirmHandler);\n editor.listeners.add(cancelBtn, 'click', cancelHandler);\n\n wrapper.appendChild(message);\n\n if (settings.type == 'prompt') {\n\n wrapper.appendChild(input);\n\n }\n\n wrapper.appendChild(okBtn);\n\n if (settings.type == 'prompt' || settings.type == 'confirm') {\n\n wrapper.appendChild(cancelBtn);\n\n }\n\n wrapper.classList.add('cdx-notification-' + settings.type);\n wrapper.dataset.type = settings.type;\n\n notification = wrapper;\n type = settings.type;\n confirm = settings.confirm;\n cancel = settings.cancel;\n inputField = input;\n\n if (settings.type != 'prompt' && settings.type != 'confirm') {\n\n window.setTimeout(close, settings.time);\n\n }\n\n };\n\n function send() {\n\n editor.nodes.notifications.appendChild(notification);\n inputField.focus();\n\n editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\n\n window.setTimeout(function () {\n\n editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n\n }, 100);\n\n addToQueue({type: type, close: close});\n\n };\n\n function close() {\n\n notification.remove();\n\n };\n\n\n if (constructorSettings) {\n\n create(constructorSettings);\n send();\n\n }\n\n return {\n create: create,\n send: send,\n close: close\n };\n\n };\n\n notifications.clear = function () {\n\n editor.nodes.notifications.innerHTML = '';\n queue = [];\n\n };\n\n return notifications;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/notifications.js","/**\n * Codex Editor Parser Module\n *\n * @author Codex Team\n * @version 1.1\n */\n\nmodule.exports = (function (parser) {\n\n let editor = codex.editor;\n\n /** inserting text */\n parser.insertPastedContent = function (blockType, tag) {\n\n editor.content.insertBlock({\n type : blockType.type,\n block : blockType.render({\n text : tag.innerHTML\n })\n });\n\n };\n\n /**\n * Check DOM node for display style: separated block or child-view\n */\n parser.isFirstLevelBlock = function (node) {\n\n return node.nodeType == editor.core.nodeTypes.TAG &&\n node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n\n };\n\n return parser;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/parser.js","/**\n * Codex Sanitizer\n */\n\nmodule.exports = (function (sanitizer) {\n\n var janitor = require('html-janitor');\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.

  • ...); if\n // they are, we want to unwrap the inner block element.\n var isNotTopContainer = !! parentNode.parentNode;\n var isNestedBlockElement =\n isBlockElement(parentNode) &&\n isBlockElement(node) &&\n isNotTopContainer;\n\n var nodeName = node.nodeName.toLowerCase();\n\n var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\n var isInvalid = isInline && containsBlockElement;\n\n // Drop tag entirely according to the whitelist *and* if the markup\n // is invalid.\n if (isInvalid || shouldRejectNode(node, allowedAttrs)\n || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n // Do not keep the inner text of SCRIPT/STYLE elements.\n if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n while (node.childNodes.length > 0) {\n parentNode.insertBefore(node.childNodes[0], node);\n }\n }\n parentNode.removeChild(node);\n\n this._sanitize(parentNode);\n break;\n }\n\n // Sanitize attributes\n for (var a = 0; a < node.attributes.length; a += 1) {\n var attr = node.attributes[a];\n\n if (shouldRejectAttr(attr, allowedAttrs, node)) {\n node.removeAttribute(attr.name);\n // Shift the array to continue looping.\n a = a - 1;\n }\n }\n\n // Sanitize children\n this._sanitize(node);\n\n // Mark node as sanitized so it's ignored in future runs\n node._sanitized = true;\n } while ((node = treeWalker.nextSibling()));\n };\n\n function createTreeWalker(node) {\n return document.createTreeWalker(node,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n null, false);\n }\n\n function getAllowedAttrs(config, nodeName, node){\n if (typeof config.tags[nodeName] === 'function') {\n return config.tags[nodeName](node);\n } else {\n return config.tags[nodeName];\n }\n }\n\n function shouldRejectNode(node, allowedAttrs){\n if (typeof allowedAttrs === 'undefined') {\n return true;\n } else if (typeof allowedAttrs === 'boolean') {\n return !allowedAttrs;\n }\n\n return false;\n }\n\n function shouldRejectAttr(attr, allowedAttrs, node){\n var attrName = attr.name.toLowerCase();\n\n if (allowedAttrs === true){\n return false;\n } else if (typeof allowedAttrs[attrName] === 'function'){\n return !allowedAttrs[attrName](attr.value, node);\n } else if (typeof allowedAttrs[attrName] === 'undefined'){\n return true;\n } else if (allowedAttrs[attrName] === false) {\n return true;\n } else if (typeof allowedAttrs[attrName] === 'string') {\n return (allowedAttrs[attrName] !== attr.value);\n }\n\n return false;\n }\n\n return HTMLJanitor;\n\n}));\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/html-janitor/src/html-janitor.js\n// module id = 18\n// module chunks = 0","/**\n * Codex Editor Anchors module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = function (anchors) {\n\n let editor = codex.editor;\n\n anchors.input = null;\n anchors.currentNode = null;\n\n anchors.settingsOpened = function (currentBlock) {\n\n anchors.currentNode = currentBlock;\n anchors.input.value = anchors.currentNode.dataset.anchor || '';\n\n };\n\n anchors.anchorChanged = function (e) {\n\n var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);\n\n anchors.currentNode.dataset.anchor = newAnchor;\n\n if (newAnchor.trim() !== '') {\n\n anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\n } else {\n\n anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);\n\n }\n\n };\n\n anchors.keyDownOnAnchorInput = function (e) {\n\n if (e.keyCode == editor.core.keys.ENTER) {\n\n e.preventDefault();\n e.stopPropagation();\n\n e.target.blur();\n editor.toolbar.settings.close();\n\n }\n\n };\n\n anchors.keyUpOnAnchorInput = function (e) {\n\n if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {\n\n e.stopPropagation();\n\n }\n\n };\n\n anchors.rusToTranslit = function (string) {\n\n var ru = [\n 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й',\n 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф',\n 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'\n ],\n en = [\n 'A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y',\n 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F',\n 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya'\n ];\n\n for (var i = 0; i < ru.length; i++) {\n\n string = string.split(ru[i]).join(en[i]);\n string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());\n\n }\n\n string = string.replace(/[^0-9a-zA-Z_]+/g, '-');\n\n return string;\n\n };\n\n return anchors;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/anchors.js","/**\n * Codex Editor Listeners module\n *\n * @author Codex Team\n * @version 1.0\n */\n\n/**\n * Module-decorator for event listeners assignment\n */\nmodule.exports = function (listeners) {\n\n var allListeners = [];\n\n /**\n * Search methods\n *\n * byElement, byType and byHandler returns array of suitable listeners\n * one and all takes element, eventType, and handler and returns first (all) suitable listener\n *\n */\n listeners.search = function () {\n\n var byElement = function (element, context) {\n\n var listenersOnElement = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.element === element) {\n\n listenersOnElement.push(listener);\n\n }\n\n }\n\n return listenersOnElement;\n\n };\n\n var byType = function (eventType, context) {\n\n var listenersWithType = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.type === eventType) {\n\n listenersWithType.push(listener);\n\n }\n\n }\n\n return listenersWithType;\n\n };\n\n var byHandler = function (handler, context) {\n\n var listenersWithHandler = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.handler === handler) {\n\n listenersWithHandler.push(listener);\n\n }\n\n }\n\n return listenersWithHandler;\n\n };\n\n var one = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result[0];\n\n };\n\n var all = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result;\n\n };\n\n return {\n byElement : byElement,\n byType : byType,\n byHandler : byHandler,\n one : one,\n all : all\n };\n\n }();\n\n listeners.add = function (element, eventType, handler, isCapture) {\n\n element.addEventListener(eventType, handler, isCapture);\n\n var data = {\n element: element,\n type: eventType,\n handler: handler\n };\n\n var alreadyAddedListener = listeners.search.one(element, eventType, handler);\n\n if (!alreadyAddedListener) {\n\n allListeners.push(data);\n\n }\n\n };\n\n listeners.remove = function (element, eventType, handler) {\n\n element.removeEventListener(eventType, handler);\n\n var existingListeners = listeners.search.all(element, eventType, handler);\n\n for (var i = 0; i < existingListeners.length; i++) {\n\n var index = allListeners.indexOf(existingListeners[i]);\n\n if (index > 0) {\n\n allListeners.splice(index, 1);\n\n }\n\n }\n\n };\n\n listeners.removeAll = function () {\n\n allListeners.map(function (current) {\n\n listeners.remove(current.element, current.type, current.handler);\n\n });\n\n };\n\n listeners.get = function (element, eventType, handler) {\n\n return listeners.search.all(element, eventType, handler);\n\n };\n\n return listeners;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/listeners.js","/**\n * Codex Editor Destroyer module\n *\n * @auhor Codex Team\n * @version 1.0\n */\n\nmodule.exports = function (destroyer) {\n\n let editor = codex.editor;\n\n destroyer.removeNodes = function () {\n\n editor.nodes.wrapper.remove();\n editor.nodes.notifications.remove();\n\n };\n\n destroyer.destroyPlugins = function () {\n\n for (var tool in editor.tools) {\n\n if (typeof editor.tools[tool].destroy === 'function') {\n\n editor.tools[tool].destroy();\n\n }\n\n }\n\n };\n\n destroyer.destroyScripts = function () {\n\n var scripts = document.getElementsByTagName('SCRIPT');\n\n for (var i = 0; i < scripts.length; i++) {\n\n if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n\n scripts[i].remove();\n i--;\n\n }\n\n }\n\n };\n\n\n /**\n * Delete editor data from webpage.\n * You should send settings argument with boolean flags:\n * @param settings.ui- remove redactor event listeners and DOM nodes\n * @param settings.scripts - remove redactor scripts from DOM\n * @param settings.plugins - remove plugin's objects\n * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\n * }\n *\n */\n destroyer.destroy = function (settings) {\n\n if (!settings || typeof settings !== 'object') {\n\n return;\n\n }\n\n if (settings.ui) {\n\n destroyer.removeNodes();\n editor.listeners.removeAll();\n\n }\n\n if (settings.scripts) {\n\n destroyer.destroyScripts();\n\n }\n\n if (settings.plugins) {\n\n destroyer.destroyPlugins();\n\n }\n\n if (settings.ui && settings.scripts && settings.core) {\n\n delete codex.editor;\n\n }\n\n };\n\n return destroyer;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/destroyer.js","/**\n * Codex Editor Paste module\n *\n * @author Codex Team\n * @version 1.1.1\n */\n\nmodule.exports = function (paste) {\n\n let editor = codex.editor;\n\n var patterns = [];\n\n paste.prepare = function () {\n\n var tools = editor.tools;\n\n for (var tool in tools) {\n\n if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n\n continue;\n\n }\n\n tools[tool].renderOnPastePatterns.map(function (pattern) {\n\n\n patterns.push(pattern);\n\n });\n\n }\n\n return Promise.resolve();\n\n };\n\n /**\n * Saves data\n * @param event\n */\n paste.pasted = function (event) {\n\n var clipBoardData = event.clipboardData || window.clipboardData,\n content = clipBoardData.getData('Text');\n\n var result = analize(content);\n\n if (result) {\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n }\n\n return result;\n\n };\n\n /**\n * Analizes pated string and calls necessary method\n */\n\n var analize = function (string) {\n\n var result = false,\n content = editor.content.currentNode,\n plugin = content.dataset.tool;\n\n patterns.map( function (pattern) {\n\n var execArray = pattern.regex.exec(string),\n match = execArray && execArray[0];\n\n if ( match && match === string.trim()) {\n\n /** current block is not empty */\n if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {\n\n pasteToNewBlock_();\n\n }\n\n pattern.callback(string, pattern);\n result = true;\n\n }\n\n });\n\n return result;\n\n };\n\n var pasteToNewBlock_ = function () {\n\n /** Create new initial block */\n editor.content.insertBlock({\n\n type : editor.settings.initialBlockPlugin,\n block : editor.tools[editor.settings.initialBlockPlugin].render({\n text : ''\n })\n\n }, false);\n\n };\n\n return paste;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/paste.js"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///codex-editor.js","webpack:///webpack/bootstrap d53b65d3ebbd53c620c1","webpack:///./codex.js","webpack:///./modules/core.js","webpack:///./modules/tools.js","webpack:///./modules/ui.js","webpack:///./modules/transport.js","webpack:///./modules/renderer.js","webpack:///./modules/saver.js","webpack:///./modules/content.js","webpack:///./modules/toolbar/toolbar.js","webpack:///./modules/toolbar/settings.js","webpack:///./modules/toolbar/inline.js","webpack:///./modules/toolbar/toolbox.js","webpack:///./modules/callbacks.js","webpack:///./modules/draw.js","webpack:///./modules/caret.js","webpack:///./modules/notifications.js","webpack:///./modules/parser.js","webpack:///./modules/sanitizer.js","webpack:///./~/html-janitor/src/html-janitor.js","webpack:///./modules/anchors.js","webpack:///./modules/listeners.js","webpack:///./modules/destroyer.js","webpack:///./modules/paste.js"],"names":["codex","modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","editor","version","scriptPrefix","init","core","tools","ui","transport","renderer","saver","content","toolbar","callback","draw","caret","notifications","parser","sanitizer","anchors","listeners","destroyer","paste","settings","textareaId","uploadImagesUrl","initialBlockPlugin","nodes","textarea","wrapper","inlineToolbar","buttons","actions","toolbox","plusButton","showSettingsButton","showTrashButton","blockSettings","pluginSettings","defaultSettings","toolbarButtons","redactor","state","jsonOutput","blocks","inputs","start","userSettings","prepare","then","make","addTools","bindEvents","makeBlocksFromData","saveInputs","catch","error","log","_typeof","Symbol","iterator","obj","constructor","prototype","Promise","resolve","reject","data","hideToolbar","document","getElementById","undefined","Error","msg","type","arg","window","console","e","insertAfter","target","element","parentNode","insertBefore","nextSibling","nodeTypes","TAG","TEXT","COMMENT","keys","BACKSPACE","TAB","ENTER","SHIFT","CTRL","ALT","ESC","SPACE","LEFT","UP","DOWN","RIGHT","DELETE","META","isDomNode","el","nodeType","this","isEmpty","Object","length","ajax","url","XMLHTTP","XMLHttpRequest","ActiveXObject","successFunction","params","async","success","test","encodeURIComponent","withCredentials","beforeSend","open","setRequestHeader","onreadystatechange","readyState","status","responseText","send","importScript","scriptPath","instanceName","script","createElement","defer","onload","onerror","src","head","appendChild","resolve_","reject_","pluginsRequiresPreparation","allPlugins","pluginName","plugin","push","waitAllPluginsPreparation_","plugins","allPluginsProcessed__","reduce","previousValue","iteration","pluginIsReady__","callPluginsPrepareMethod_","available","loadingMessage","config","className","BLOCK_CLASSNAME","BLOCK_CONTENT","BLOCK_STRETCHED","BLOCK_HIGHLIGHTED","BLOCK_IN_FEED_MODE","BLOCK_WITH_ANCHOR","SETTINGS_ITEM","toolbarContent","blockButtons","createHolder","settingsButton","makeRemoveBlockButton","pluginsSettings","makeInlineToolbar","addDefaultSettings","container","inlineToolbarButtons","inlineToolbarActions","tool","toolName","toolButton","iconClassname","displayInToolbox","render","toolbarButton","addInlineToolbarTools","bold","icon","command","italic","underline","link","name","toolbarButtonInline","setInlineToolbarButtonBehaviour","add","globalKeydown","redactorKeyDown","globalKeyup","redactorClicked","plusButtonClicked","showSettingsButtonClicked","button","toolbarButtonClicked","addBlockHandlers","block","blockKeydown","blockPasteCallback","inline","show","querySelectorAll","Array","map","current","addInitialBlock","initialBlock","initialBlockType","setAttribute","insertBlock","workingNodeChanged","event","toolClicked","input","arguments","fileSelected","clearInput","files","formdData","FormData","append","selectAndUpload","args","click","xhr","items","appendBlocks","nodeSequence","index","appendNodeAtIndex","getNodeAsync","createBlockFromData","blockData","blocksList","position","toolData","anchor","cover","unavailableBlock","innerHTML","dataset","inputPosition","stretched","isStretched","saveBlocks","html","childNodes","makeQueue","queue","getBlockData","makeFormDataFromBlocks","save","savedData","output","blockContent","pluginsContent","coverFlag","classList","contains","validate","result","currentNode","editorAreaHightlighted","sync","getNodeFocused","focused","selection","getSelection","anchorNode","focusNode","parentElement","isFirstLevelBlock","parent","markBlock","clearMark","remove","getFirstLevelBlock","node","body","targetNode","replaceBlock","targetBlock","newBlock","replaceChild","needPlaceCaret","workingBlock","newBlockContent","blockType","composeNewBlock","currentInputIndex","getCurrentInputIndex","editableElement","querySelector","emptyText","createTextNode","set","move","showPlusButton","setTimeout","setToNextBlock","switchBlock","blockToReplace","newBlockComposed","getDeepestTextNodeFromPosition","text","blockChilds","textContent","trim","removeChild","lookingFromStart","getRange","getRangeAt","splitBlock","inputIndex","textBeforeCaret","textNodeBeforeCaret","textAfterCaret","textNodeAfterCaret","anchorNodeText","caretOffset","anchorOffset","currentBlock","substring","previousChilds","nextChilds","reachedCurrent","child","i","previousChildsLength","nextChildsLength","newNode","NEW_BLOCK_TYPE","mergeBlocks","targetInputIndex","targetInput","currentInputContent","mutation","workingNode","allowedToPaste","sanitize","pasteTextContent","addedNodes","textNode","disconnect","cleaner","satinizer","Config","BASIC","clean","outerHTML","div","replaceWith","isLastNode","allChecked","allSiblingsEmpty_","sibling","wrapTextWithParagraphs","htmlString","paragraph","blockTyped","newWrapper","firstLevelBlocks","indexOf","tagName","cloneNode","getEditableParent","contentEditable","defaultToolbarHeight","defaultOffset","opened","close","toggle","hidePlusButton","newYCoordinate","offsetTop","style","transform","Math","floor","hideRemoveActions","setting","toolType","makeSettings","settingsBlock","settingsOpened","feedModeToggler","anchorInput","makeFeedModeToggler","makeAnchorInput","isFeedModeActivated","updateFeedMode","anchorWrapper","hash","placeholder","keyDownOnAnchorInput","keyUpOnAnchorInput","anchorChanged","removeBlockWrapper","settingButton","actionWrapper","confirmAction","cancelAction","removeButtonClicked","confirmRemovingRequest","cancelRemovingRequest","action","showRemoveActions","firstLevelBlocksCount","buttonsOpened","actionsOpened","wrappersOffset","storedSelection","showInlineToolbar","selectedText","getSelectionText","showButtons","getWrappersOffset","newCoordinateX","newCoordinateY","coords","getSelectionCoords","offsetHeight","x","left","y","scrollY","top","closeButtons","closeAction","createLinkAction","defaultToolAction","forEach","hightlight","offset","getOffset","_x","_y","isNaN","offsetLeft","clientLeft","clientTop","offsetParent","range","sel","createRange","collapse","boundingLeft","boundingTop","rangeCount","cloneRange","getClientRects","rect","toString","showActions","inlineToolbarAnchorInputKeydown_","keyCode","editable","restoreSelection","setAnchor","value","preventDefault","stopImmediatePropagation","clearRange","isActive","isLinkActive","saveSelection","inputForLink","focus","dataType","execCommand","containerEl","preSelectionRange","selectNodeContents","setEnd","startContainer","startOffset","end","savedSel","charIndex","setStart","nextCharIndex","nodeStack","foundStart","stop","pop","removeAllRanges","addRange","queryCommandState","setButtonHighlighted","removeButtonsHighLight","tag","leaf","currentTool","barButtons","nextToolIndex","toolToSelect","visibleTool","appendCallback","UNREPLACEBLE_TOOLS","setToBlock","callbacks","enterKeyPressed","tabKeyPressed","enterKeyPressedOnRedactorZone","escapeKeyPressed","defaultKeyPressed","arrowKeyPressed","inputsAreEmpty","textContentIsEmpty","blockIsEmpty","enterPressedOnBlock","saveCurrentInputIndex","isEnterPressedOnToolbar","enableLineBreaks","stopPropagation","shiftKey","currentSelection","currentSelectedNode","caretAtTheEndOfText","atTheEnd","isTextNodeHasParentBetweenContenteditable","islastNode","detectWhenClickedOnFirstLevelBlockArea","firstLevelBlock","indexOfLastInput","inputIsEmpty","currentNodeType","isInitialType","flag","blockRightOrDownArrowPressed","backspacePressed","blockLeftOrUpArrowPressed","focusedNodeHolder","focusedNode","editableElementIndex","lastChild","deepestTextnode","caretInLastChild","firstChild","caretInFirstChild","caretAtTheBeginning","setToPreviousBlock","selectionLength","isNativeInput","endOffset","atStart","_blockPasteCallback","observer","MutationObserver","handleMutationsOnPaste","attributes","childList","characterData","subtree","observe","editableParent","cleanData","fragment","htmlData","clipboardData","getData","plainData","createDocumentFragment","innerText","lastNode","allowRenderOnPaste","pasted","deleteContents","insertNode","setStartAfter","mutations","self","currentToolType","nativeInputAreas","ceBlock","bar","toggler","classname","toolIcon","toolTitle","properties","focusedNodeIndex","nodeToSet","childs","nextInput","emptyTextElement","lastChildNode","lengthOfLastChildNode","previousInput","pluginsRender","isFirstNode","isOffsetZero","addToQueue","splice","holder","errorThrown","errorMsg","notification","message","constructorSettings","create","time","okBtn","cancelBtn","okMsg","cancelMsg","confirmHandler","cancelHandler","confirm","cancel","inputField","clear","insertPastedContent","janitor","tags","a","href","rel","b","strong","em","span","__WEBPACK_AMD_DEFINE_FACTORY__","__WEBPACK_AMD_DEFINE_RESULT__","root","factory","HTMLJanitor","tagDefinitions","validConfigValues","k","every","isBlockElement","blockElementNames","nodeName","isInlineElement","inlineElementNames","createTreeWalker","NodeFilter","SHOW_TEXT","SHOW_ELEMENT","SHOW_COMMENT","getAllowedAttrs","shouldRejectNode","allowedAttrs","shouldRejectAttr","attr","attrName","toLowerCase","sandbox","_sanitize","treeWalker","_sanitized","Node","TEXT_NODE","COMMENT_NODE","containsBlockElement","isInline","some","isNotTopContainer","isNestedBlockElement","isInvalid","keepNestedBlockElements","removeAttribute","previousElementSibling","nextElementSibling","newAnchor","rusToTranslit","blur","string","ru","en","split","join","replace","allListeners","search","byElement","context","listenersOnElement","listener","byType","eventType","listenersWithType","byHandler","handler","listenersWithHandler","one","all","isCapture","addEventListener","alreadyAddedListener","removeEventListener","existingListeners","removeAll","get","removeNodes","destroyPlugins","destroy","destroyScripts","scripts","getElementsByTagName","patterns","renderOnPastePatterns","isArray","pattern","clipBoardData","analize","execArray","regex","exec","match","pasteToNewBlock_"],"mappings":"AAAA,GAAIA,OAAQA,SAAaA,OAAc,OAC9B,SAAUC,GCGnB,QAAAC,GAAAC,GAGA,GAAAC,EAAAD,GACA,MAAAC,GAAAD,GAAAE,OAGA,IAAAC,GAAAF,EAAAD,IACAE,WACAE,GAAAJ,EACAK,QAAA,EAUA,OANAP,GAAAE,GAAAM,KAAAH,EAAAD,QAAAC,IAAAD,QAAAH,GAGAI,EAAAE,QAAA,EAGAF,EAAAD,QAvBA,GAAAD,KAqCA,OATAF,GAAAQ,EAAAT,EAGAC,EAAAS,EAAAP,EAGAF,EAAAU,EAAA,GAGAV,EAAA,KDOM,SAASI,EAAQD,EAASH,GAE/B,YExCDI,GAAOD,QAAW,SAAUQ,GAIxBA,EAAOC,QAAU,QACjBD,EAAOE,aAAe,aAEtB,IAAIC,GAAO,WAEPH,EAAOI,KAAgBf,EAAQ,GAC/BW,EAAOK,MAAgBhB,EAAQ,GAC/BW,EAAOM,GAAgBjB,EAAQ,GAC/BW,EAAOO,UAAgBlB,EAAQ,GAC/BW,EAAOQ,SAAgBnB,EAAQ,GAC/BW,EAAOS,MAAgBpB,EAAQ,GAC/BW,EAAOU,QAAgBrB,EAAQ,GAC/BW,EAAOW,QAAgBtB,EAAQ,GAC/BW,EAAOY,SAAgBvB,EAAQ,IAC/BW,EAAOa,KAAgBxB,EAAQ,IAC/BW,EAAOc,MAAgBzB,EAAQ,IAC/BW,EAAOe,cAAgB1B,EAAQ,IAC/BW,EAAOgB,OAAgB3B,EAAQ,IAC/BW,EAAOiB,UAAgB5B,EAAQ,IAC/BW,EAAOkB,QAAgB7B,EAAQ,IAC/BW,EAAOmB,UAAgB9B,EAAQ,IAC/BW,EAAOoB,UAAgB/B,EAAQ,IAC/BW,EAAOqB,MAAgBhC,EAAQ,IAmHnC,OA1GAW,GAAOsB,UACHjB,OAAa,YAAa,SAAU,UAAW,OAAQ,QAAS,OAAQ,UAAW,YAAa,SAChGkB,WAAY,eACZC,gBAAiB,qBAGjBC,mBAAoB,aAQxBzB,EAAO0B,OACHC,SAAoB,KACpBC,QAAoB,KACpBjB,QAAoB,KACpBkB,eACID,QAAU,KACVE,QAAU,KACVC,QAAU,MAEdC,QAAoB,KACpBjB,cAAoB,KACpBkB,WAAoB,KACpBC,mBAAoB,KACpBC,gBAAoB,KACpBC,cAAoB,KACpBC,eAAoB,KACpBC,gBAAoB,KACpBC,kBACAC,SAAoB,MAQxBxC,EAAOyC,OACHC,cACAC,UACAC,WAOJ5C,EAAOK,SAiCPL,EAAO6C,MAAQ,SAAUC,GAErB3C,IAEAH,EAAOI,KAAK2C,QAAQD,GAGfE,KAAKhD,EAAOM,GAAG2C,MACfD,KAAKhD,EAAOM,GAAG4C,UACfF,KAAKhD,EAAOM,GAAG6C,YACfH,KAAKhD,EAAOK,MAAM0C,SAClBC,KAAKhD,EAAOqB,MAAM0B,SAClBC,KAAKhD,EAAOO,UAAUwC,SACtBC,KAAKhD,EAAOQ,SAAS4C,oBACrBJ,KAAKhD,EAAOM,GAAG+C,YACfC,MAAM,SAAUC,GAEbvD,EAAOI,KAAKoD,IAAI,uCAAwC,OAAQD,MAMrEvD,QF2CL,SAASP,EAAQD,GAEtB,YAEA,IAAIiE,GAA4B,kBAAXC,SAAoD,gBAApBA,QAAOC,SAAwB,SAAUC,GAAO,aAAcA,IAAS,SAAUA,GAAO,MAAOA,IAAyB,kBAAXF,SAAyBE,EAAIC,cAAgBH,QAAUE,IAAQF,OAAOI,UAAY,eAAkBF,GG5LvQnE,GAAOD,QAAW,SAAUY,GAExB,GAAIJ,GAASb,MAAMa,MAuPnB,OA/OAI,GAAK2C,QAAU,SAAUD,GAErB,MAAO,IAAIiB,SAAQ,SAAUC,EAASC,GAE7BnB,IAED9C,EAAOsB,SAASjB,MAAQyC,EAAazC,OAASL,EAAOsB,SAASjB,OAI9DyC,EAAaoB,OAEblE,EAAOyC,MAAME,OAASG,EAAaoB,MAInCpB,EAAarB,qBAEbzB,EAAOsB,SAASG,mBAAqBqB,EAAarB,oBAIlDqB,EAAatB,kBAEbxB,EAAOsB,SAASE,gBAAkBsB,EAAatB,iBAInDxB,EAAOmE,YAAcrB,EAAaqB,YAElCnE,EAAO0B,MAAMC,SAAWyC,SAASC,eAAevB,EAAavB,YAAcvB,EAAOsB,SAASC,YAEtD+C,SAAjCb,EAAOzD,EAAO0B,MAAMC,WAAoD,OAA1B3B,EAAO0B,MAAMC,SAE3DsC,EAAOM,MAAM,iCAAmCzB,EAAavB,aAI7DyC,OAYZ5D,EAAKoD,IAAM,SAAUgB,EAAKC,EAAMC,GAE5BD,EAAOA,GAAQ,MAEVC,EAODF,EAAO,wBAA0BA,GALjCE,EAAOF,GAAO,YACdA,EAAO,0BAQX,KAES,WAAaG,SAAUA,OAAOC,QAASH,KAEnCC,EAAMC,OAAOC,QAASH,GAAQD,EAAKE,GACnCC,OAAOC,QAASH,GAAQD,IAIpC,MAAMK,MASXzE,EAAK0E,YAAc,SAAUC,EAAQC,GAEjCD,EAAOE,WAAWC,aAAaF,EAASD,EAAOI,cASnD/E,EAAKgF,WACDC,IAAU,EACVC,KAAU,EACVC,QAAU,GAOdnF,EAAKoF,MAASC,UAAW,EAAGC,IAAK,EAAGC,MAAO,GAAIC,MAAO,GAAIC,KAAM,GAAIC,IAAK,GAAIC,IAAK,GAAIC,MAAO,GAAIC,KAAM,GAAIC,GAAI,GAAIC,KAAM,GAAIC,MAAO,GAAIC,OAAQ,GAAIC,KAAM,IAO1JlG,EAAKmG,UAAY,SAAUC,GAEvB,MAAOA,IAAoB,YAAd,mBAAOA,GAAP,YAAA/C,EAAO+C,KAAmBA,EAAGC,UAAYD,EAAGC,UAAYC,KAAKtB,UAAUC,KASxFjF,EAAKuG,QAAU,SAAW/C,GAEtB,MAAmC,KAA5BgD,OAAOpB,KAAK5B,GAAKiD,QAO5BzG,EAAK0G,KAAO,SAAU5C,GAElB,GAAKA,GAASA,EAAK6C,IAAnB,CAMA,GAGInD,GAHAoD,EAAmBrC,OAAOsC,eAAiB,GAAIA,gBAAmB,GAAIC,eAAc,qBACpFC,EAAkB,aAClBC,EAAS,EASb,IANAlD,EAAKmD,OAAkB,EACvBnD,EAAKO,KAAkBP,EAAKO,MAAQ,MACpCP,EAAKA,KAAkBA,EAAKA,MAAQ,GACpCA,EAAK,gBAAkBA,EAAK,iBAAmB,kCAC/CiD,EAAsBjD,EAAKoD,SAAWH,EAErB,OAAbjD,EAAKO,MAAiBP,EAAKA,KAE3BA,EAAK6C,IAAM,KAAKQ,KAAKrD,EAAK6C,KAAO7C,EAAK6C,IAAM,IAAM7C,EAAKA,KAAOA,EAAK6C,IAAM,IAAM7C,EAAKA,SAIpF,KAAIN,IAAOM,GAAKA,KAEZkD,GAAWxD,EAAM,IAAM4D,mBAAmBtD,EAAKA,KAAKN,IAAQ,GAMhEM,GAAKuD,kBAELT,EAAQS,iBAAkB,GAI1BvD,EAAKwD,YAAwC,kBAAnBxD,GAAKwD,YAE/BxD,EAAKwD,WAAW9H,OAIpBoH,EAAQW,KAAMzD,EAAKO,KAAMP,EAAK6C,IAAK7C,EAAKmD,OACxCL,EAAQY,iBAAiB,mBAAoB,kBAC7CZ,EAAQY,iBAAiB,eAAgB,qCAEzCZ,EAAQa,mBAAqB,WAEC,GAAtBb,EAAQc,YAAqC,KAAlBd,EAAQe,QAEnCZ,EAAgBH,EAAQgB,eAMhChB,EAAQiB,KAAKb,KAQjBhH,EAAK8H,aAAe,SAAUC,EAAYC,GAEtC,MAAO,IAAIrE,SAAQ,SAAUC,EAASC,GAElC,GAAIoE,SAGED,GAIMhE,SAASC,eAAerE,EAAOE,aAAekI,IAEtDpE,EAAQmE,GAJRlE,EAAO,2BAQXoE,EAASjE,SAASkE,cAAc,UAChCD,EAAOhB,OAAQ,EACfgB,EAAOE,OAAQ,EACfF,EAAO3I,GAAKM,EAAOE,aAAekI,EAElCC,EAAOG,OAAS,WAEZxE,EAAQmE,IAIZE,EAAOI,QAAU,WAEbxE,EAAOkE,IAIXE,EAAOK,IAAMP,EACb/D,SAASuE,KAAKC,YAAYP,MAM3BjI,QH0KL,SAASX,EAAQD,GAEtB,YIzaDC,GAAOD,QAAW,WASd,QAASuD,KAEL,MAAO,IAAIgB,SAAQ,SAAU8E,EAAUC,GAEnC/E,QAAQC,UAKHhB,KAAK,WAEF,GAAI+F,MACAC,EAAahJ,EAAOK,KAExB,KAAM,GAAI4I,KAAcD,GAAa,CAEjC,GAAIE,GAASF,EAAWC,EAEpBC,GAAOnG,SAAoC,kBAAlBmG,GAAOnG,UAA0BmG,EAAOnG,SAMrEgG,EAA2BI,KAAKD,GAapC,MANKH,GAA2BlC,QAE5BgC,IAIGE,IAKV/F,KAAKoG,GAELpG,KAAK,WAEFhD,EAAOI,KAAKoD,IAAI,iBAAkB,QAClCqF,MAEDvF,MAAM,SAAUC,GAEfuF,EAAQvF,OAYxB,QAAS6F,GAA2BC,GAKhC,MAAO,IAAItF,SAAS,SAAUuF,GAW1BD,EAAQE,OAAO,SAAUC,EAAeN,EAAQO,GAE5C,MAAOD,GAAcxG,KAAK,WAMtB,MAAO,IAAIe,SAAU,SAAU2F,GAE3BC,EAA2BT,GAEtBlG,KAAM0G,GACN1G,KAAM,WAEHkG,EAAOU,WAAY,IAItBtG,MAAM,SAAUC,GAEbvD,EAAOI,KAAKoD,IAAZ,WAA2B0F,EAAOzE,KAAlC,kDAAyF,OAAQlB,GACjG2F,EAAOU,WAAY,EACnBV,EAAOW,eAAiBtG,EAGxBmG,MAIH1G,KAAK,WAGEyG,GAAaJ,EAAQxC,OAAS,GAE9ByC,WAUrBvF,QAAQC,aAnInB,GAAIhE,GAASb,MAAMa,OAyIf2J,EAA4B,SAAUT,GAEtC,MAAOA,GAAOnG,QAASmG,EAAOY,YAIlC,QACI/G,QAASA,OJyZX,SAAStD,EAAQD,GAEtB,YKziBDC,GAAOD,QAAW,SAAUc,GAExB,GAAIN,GAASb,MAAMa,MA+YnB,OA1YAM,GAAGyJ,WAKCC,gBAAkB,WAKlBC,cAAgB,oBAKhBC,gBAAkB,sBAKlBC,kBAAoB,oBAKpBC,mBAAqB,sBAKrBC,kBAAoB,mBAKpBC,cAAgB,qBASpBhK,EAAG2C,KAAO,WAEN,GAAIrB,GACAjB,EACA4J,EACA/H,EACAgI,EACApI,EACAF,EACAC,EACAH,EACAC,CAGJL,GAAU5B,EAAOa,KAAKe,UAGtB5B,EAAOI,KAAK0E,YAAY9E,EAAO0B,MAAMC,SAAUC,GAG/C5B,EAAOe,cAAc0J,eAGrB9J,EAAwBX,EAAOa,KAAKF,UACpC4J,EAAwBvK,EAAOa,KAAK0J,iBACpCtI,EAAwBjC,EAAOa,KAAKoB,aACpCC,EAAwBlC,EAAOa,KAAK6J,iBACpCvI,EAAwBnC,EAAOW,QAAQW,SAASqJ,wBAChDvI,EAAwBpC,EAAOa,KAAKuB,gBACpCoI,EAAwBxK,EAAOa,KAAK2J,eACpCxI,EAAwBhC,EAAOa,KAAKmB,UACpCQ,EAAwBxC,EAAOa,KAAK2B,UAGpC,IAAIF,GAAkBtC,EAAOa,KAAKyB,kBAC9BD,EAAkBrC,EAAOa,KAAK+J,iBAGlCxI,GAAcwG,YAAYvG,GAC1BD,EAAcwG,YAAYtG,GAK1BkI,EAAa5B,YAAY1G,GACzBsI,EAAa5B,YAAYzG,GACzBqI,EAAa5B,YAAYxG,GAGzBmI,EAAe3B,YAAY3G,GAG3BsI,EAAe3B,YAAY5G,GAG3BrB,EAAQiI,YAAY4B,GAGpB7J,EAAQiI,YAAY2B,GAEpB3I,EAAQgH,YAAYjI,GAEpBiB,EAAQgH,YAAYpG,GAGpBxC,EAAO0B,MAAME,QAAqBA,EAClC5B,EAAO0B,MAAMf,QAAqBA,EAClCX,EAAO0B,MAAMO,WAAqBA,EAClCjC,EAAO0B,MAAMM,QAAqBA,EAClChC,EAAO0B,MAAMU,cAAqBA,EAClCpC,EAAO0B,MAAMW,eAAqBA,EAClCrC,EAAO0B,MAAMY,gBAAqBA,EAClCtC,EAAO0B,MAAMQ,mBAAqBA,EAClClC,EAAO0B,MAAMS,gBAAqBA,EAElCnC,EAAO0B,MAAMc,SAAWA,EAGxBxC,EAAOM,GAAGuK,oBAGV7K,EAAOW,QAAQW,SAASwJ,sBAI5BxK,EAAGuK,kBAAoB,WAEnB,GAAIE,GAAY/K,EAAOa,KAAKgB,eAG5B7B,GAAO0B,MAAMG,cAAcD,QAAUmJ,EAGrC/K,EAAO0B,MAAMG,cAAcC,QAAU9B,EAAOa,KAAKmK,uBAGjDhL,EAAO0B,MAAMG,cAAcE,QAAU/B,EAAOa,KAAKoK,uBAGjDjL,EAAO0B,MAAMG,cAAcD,QAAQgH,YAAY5I,EAAO0B,MAAMG,cAAcC,SAC1E9B,EAAO0B,MAAMG,cAAcD,QAAQgH,YAAY5I,EAAO0B,MAAMG,cAAcE,SAE1E/B,EAAO0B,MAAME,QAAQgH,YAAY5I,EAAO0B,MAAMG,cAAcD,UAQhEtB,EAAG4C,SAAW,WAEV,GAAIgI,GACAC,EACAC,CAEJ,KAAMD,IAAYnL,GAAOsB,SAASjB,MAE9B6K,EAAOlL,EAAOsB,SAASjB,MAAM8K,GAE7BnL,EAAOK,MAAM8K,GAAYD,EAEpBA,EAAKG,gBAAiBH,EAAKI,iBAON,kBAAfJ,GAAKK,OAOXL,EAAKI,mBAONF,EAAapL,EAAOa,KAAK2K,cAAcL,EAAUD,EAAKG,eAEtDrL,EAAO0B,MAAMM,QAAQ4G,YAAYwC,GAEjCpL,EAAO0B,MAAMa,eAAe4I,GAAYC,GAhBxCpL,EAAOI,KAAKoD,IAAI,wCAAyC,OAAQ2H,GAPjEnL,EAAOI,KAAKoD,IAAI,iDAAkD,OAAQ2H,EAgClFnL,GAAOM,GAAGmL,yBAKdnL,EAAGmL,sBAAwB,WAEvB,GAuBIL,GACAF,EAxBA7K,GAEAqL,MACIC,KAAU,eACVC,QAAU,QAGdC,QACIF,KAAU,iBACVC,QAAU,UAGdE,WACIH,KAAU,oBACVC,QAAU,aAGdG,MACIJ,KAAU,eACVC,QAAU,cAOlB,KAAI,GAAII,KAAQ3L,GAEZ6K,EAAO7K,EAAM2L,GAEbZ,EAAapL,EAAOa,KAAKoL,oBAAoBD,EAAMd,EAAKS,MAExD3L,EAAO0B,MAAMG,cAAcC,QAAQ8G,YAAYwC,GAI/CpL,EAAOM,GAAG4L,gCAAgCd,EAAYF,EAAKU,UAUnEtL,EAAG6C,WAAa,WAEZnD,EAAOI,KAAKoD,IAAI,sBAAuB,QAOvCxD,EAAOmB,UAAUgL,IAAI/H,SAAU,UAAWpE,EAAOY,SAASwL,eAAe,GAGzEpM,EAAOmB,UAAUgL,IAAInM,EAAO0B,MAAMc,SAAU,UAAWxC,EAAOY,SAASyL,iBAAiB,GAGxFrM,EAAOmB,UAAUgL,IAAI/H,SAAU,QAASpE,EAAOY,SAAS0L,aAAa,GAKrEtM,EAAOmB,UAAUgL,IAAInM,EAAO0B,MAAMc,SAAU,QAASxC,EAAOY,SAAS2L,iBAAiB,GAKtFvM,EAAOmB,UAAUgL,IAAInM,EAAO0B,MAAMO,WAAY,QAASjC,EAAOY,SAAS4L,mBAAmB,GAK1FxM,EAAOmB,UAAUgL,IAAInM,EAAO0B,MAAMQ,mBAAoB,QAASlC,EAAOY,SAAS6L,2BAA2B,EAS1G,KAAK,GAAIC,KAAU1M,GAAO0B,MAAMa,eAE5BvC,EAAOmB,UAAUgL,IAAInM,EAAO0B,MAAMa,eAAemK,GAAS,QAAS1M,EAAOY,SAAS+L,sBAAsB,IAMjHrM,EAAGsM,iBAAmB,SAAUC,GAEvBA,IAKL7M,EAAOmB,UAAUgL,IAAIU,EAAO,UAAW7M,EAAOY,SAASkM,cAAc,GAqBrE9M,EAAOmB,UAAUgL,IAAIU,EAAO,QAAS7M,EAAOY,SAASmM,oBAAoB,GAEzE/M,EAAOmB,UAAUgL,IAAIU,EAAO,UAAW7M,EAAOW,QAAQqM,OAAOC,MAAM,KAKvE3M,EAAG+C,WAAa,WAEZ,GAAIb,GAAWxC,EAAO0B,MAAMc,QAE5BxC,GAAOyC,MAAMG,SAGb,IAAIA,GAASJ,EAAS0K,iBAAiB,qCAEvCC,OAAMrJ,UAAUsJ,IAAIxN,KAAKgD,EAAQ,SAAUyK,GAElCA,EAAQ5I,MAAwB,QAAhB4I,EAAQ5I,MAAkC,YAAhB4I,EAAQ5I,MAEnDzE,EAAOyC,MAAMG,OAAOuG,KAAKkE,MAWrC/M,EAAGgN,gBAAkB,WAEjB,GACIC,GADAC,EAAmBxN,EAAOsB,SAASG,kBAGvC,OAAMzB,GAAOK,MAAMmN,IAOnBD,EAAevN,EAAOK,MAAMmN,GAAkBjC,SAE9CgC,EAAaE,aAAa,mBAAoB,8BAE9CzN,EAAOU,QAAQgN,aACXjJ,KAAQ+I,EACRX,MAAQU,QAGZvN,GAAOU,QAAQiN,mBAAmBJ,QAd9BvN,GAAOI,KAAKoD,IAAI,mEAAqE,OAAQgK,IAkBrGlN,EAAG4L,gCAAkC,SAAUQ,EAAQjI,GAEnDzE,EAAOmB,UAAUgL,IAAIO,EAAQ,YAAa,SAAUkB,GAEhD5N,EAAOW,QAAQqM,OAAOa,YAAYD,EAAOnJ,KAE1C,IAIAnE,QLshBL,SAASb,EAAQD,GAEtB,YMx6BDC,GAAOD,QAAW,SAAUe,GAExB,GAAIP,GAASb,MAAMa,MAoGnB,OAlGAO,GAAUuN,MAAQ,KAKlBvN,EAAUwN,UAAY,KAEtBxN,EAAUwC,QAAU,WAEhB,GAAI+K,GAAQ1J,SAASkE,cAAc,QAEnCwF,GAAMrJ,KAAO,OACbzE,EAAOmB,UAAUgL,IAAI2B,EAAO,SAAU9N,EAAOO,UAAUyN,cAEvDhO,EAAOO,UAAUuN,MAAQA,GAK7BvN,EAAU0N,WAAa,WAGnBvH,KAAKoH,MAAQ,KAGbpH,KAAK3D,WAQTxC,EAAUyN,aAAe,WAErB,GAAIF,GAAcpH,KACdwH,EAAcJ,EAAMI,MACpBC,EAAc,GAAIC,SAEtBD,GAAUE,OAAO,QAASH,EAAM,GAAIA,EAAM,GAAGlC,MAE7ChM,EAAOO,UAAUuG,MACb5C,KAAOiK,EACPzG,WAAa1H,EAAOO,UAAUwN,UAAUrG,WACxCJ,QAAatH,EAAOO,UAAUwN,UAAUzG,QACxC/D,MAAavD,EAAOO,UAAUwN,UAAUxK,SAShDhD,EAAU+N,gBAAkB,SAAUC,GAElC7H,KAAKqH,UAAYQ,EACjB7H,KAAKoH,MAAMU,SAQfjO,EAAUuG,KAAO,SAAUM,GAEvB,GAAIqH,GAAM,GAAIxH,gBACVS,EAAyC,kBAArBN,GAAOM,WAA2BN,EAAOM,WAAa,aAC1EJ,EAAyC,kBAArBF,GAAOE,QAA2BF,EAAOE,QAAU,aACvE/D,EAAyC,kBAArB6D,GAAO7D,MAA2B6D,EAAO7D,MAAU,YAE3EmE,KAEA+G,EAAI9G,KAAK,OAAQ3H,EAAOsB,SAASE,iBAAiB,GAElDiN,EAAI7G,iBAAiB,mBAAoB,kBAEzC6G,EAAIjG,OAAS,WAEU,MAAfiG,EAAI1G,OAEJT,EAAQmH,EAAIzG,eAIZhI,EAAOI,KAAKoD,IAAI,oBAAqBiL,GACrClL,MAMRkL,EAAIxG,KAAKb,EAAOlD,MAChBwC,KAAKuH,cAIF1N,QN+6BL,SAASd,EAAQD,GAEtB,YOxhCDC,GAAOD,QAAW,SAAUgB,GAExB,GAAIR,GAASb,MAAMa,MAmMnB,OA9LAQ,GAAS4C,mBAAqB,WAK1B,MAAIpD,GAAOI,KAAKuG,QAAQ3G,EAAOyC,MAAME,UAAY3C,EAAOyC,MAAME,OAAO+L,MAAM7H,WAEvE7G,GAAOM,GAAGgN,sBAKdvJ,SAAQC,UAGHhB,KAAK,WAEF,MAAOhD,GAAOyC,MAAME,SAKvBK,KAAKhD,EAAOQ,SAASmO,cAGrBrL,MAAM,SAAUC,GAEbvD,EAAOI,KAAKoD,IAAI,+BAAgC,QAASD,MAWrE/C,EAASmO,aAAe,SAAUzK,GAU9B,IAAK,GARDvB,GAASuB,EAAKwK,MAMdE,EAAe7K,QAAQC,UAElB6K,EAAQ,EAAGA,EAAQlM,EAAOkE,OAASgI,IAGxC7O,EAAOQ,SAASsO,kBAAkBF,EAAcjM,EAAQkM,IAShErO,EAASsO,kBAAoB,SAAUF,EAAcjM,EAAQkM,GAGzDD,EAGK5L,KAAK,WAEF,MAAOhD,GAAOQ,SAASuO,aAAapM,EAAQkM,KAO/C7L,KAAKhD,EAAOQ,SAASwO,qBAKrBhM,KAAK,SAAUiM,GAQZ,MAHAjP,GAAOU,QAAQgN,YAAYuB,GAGpBA,EAAUpC,QAKpBvJ,MAAM,SAAUC,GAEbvD,EAAOI,KAAKoD,IAAI,wCAAyC,QAASD,MAU9E/C,EAASuO,aAAe,SAAUG,EAAYL,GAE1C,MAAO9K,SAAQC,UAAUhB,KAAK,WAE1B,OACIkI,KAAOgE,EAAWL,GAClBM,SAAWN,MAqBvBrO,EAASwO,oBAAsB,SAAWI,GAGtC,GAAIvC,GACA3B,EAAOkE,EAASlE,KAChBjC,EAAaiC,EAAKzG,KAClB4K,EAAanE,EAAKmE,OAClBC,EAAapE,EAAKoE,KAMtB,KAAKtP,EAAOK,MAAM4I,GAEd,KAAM1E,kBAAiB0E,EAAjB,cAKV,IAA8C,kBAAnCjJ,GAAOK,MAAM4I,GAAYsC,OAEhC,KAAMhH,kBAAiB0E,EAAjB,8BAILjJ,GAAOK,MAAM4I,GAAYW,aAAc,GAExCiD,EAAQ7M,EAAOa,KAAK0O,mBAEpB1C,EAAM2C,UAAYxP,EAAOK,MAAM4I,GAAYY,eAK3CgD,EAAM4C,QAAQC,cAAgBN,EAASD,UAKvCtC,EAAQ7M,EAAOK,MAAM4I,GAAYsC,OAAOL,EAAKhH,KAKjD,IAAIyL,GAAY3P,EAAOK,MAAM4I,GAAY2G,cAAe,CAGxD,QACInL,KAAYwE,EACZ4D,MAAYA,EACZ8C,UAAYA,EACZL,MAAYA,EACZD,OAAYA,IAKb7O,QPqhCL,SAASf,EAAQD,GAEtB,YQ5tCDC,GAAOD,QAAW,SAAUiB,GAExB,GAAIT,GAASb,MAAMa,MAiJnB,OA3IAS,GAAMoP,WAAa,WAGf7P,EAAOyC,MAAMqN,KAAO9P,EAAO0B,MAAMc,SAASgN,UAG1CxP,EAAOyC,MAAMC,cAEbqB,QAAQC,UAEHhB,KAAK,WAEF,MAAOhD,GAAO0B,MAAMc,SAASuN,aAIhC/M,KAAKhD,EAAOS,MAAMuP,WAElBhN,KAAK,cAILM,MAAO,SAAUC,GAEdvD,EAAOI,KAAKoD,IAAID,MAM5B9C,EAAMuP,UAAY,SAAUrN,GAIxB,IAAI,GAFAsN,GAAQlM,QAAQC,UAEZ6K,EAAQ,EAAGA,EAAQlM,EAAOkE,OAAQgI,IAGtC7O,EAAOS,MAAMyP,aAAaD,EAAOtN,EAAQkM,IAOjDpO,EAAMyP,aAAe,SAAUD,EAAOtN,EAAQkM,GAE1CoB,EAAMjN,KAAK,WAEP,MAAOhD,GAAOS,MAAMsO,aAAapM,EAAQkM,KAIxC7L,KAAKhD,EAAOS,MAAM0P,yBAS3B1P,EAAMsO,aAAe,SAAUG,EAAYL,GAEvC,MAAO9K,SAAQC,UAAUhB,KAAK,WAE1B,MAAOkM,GAAWL,MAM1BpO,EAAM0P,uBAAyB,SAAUtD,GAErC,GAAI5D,GAAa4D,EAAM4C,QAAQvE,KAC3BmE,EAAaxC,EAAM4C,QAAQJ,MAG/B,KAAKrP,EAAOK,MAAM4I,GAEd,KAAM1E,kBAAiB0E,EAAjB,cAKV,IAA4C,kBAAjCjJ,GAAOK,MAAM4I,GAAYmH,KAEhC,KAAM7L,kBAAiB0E,EAAjB,0BAKV,IAEIoH,GACAlB,EACAmB,EAJAC,EAAiB1D,EAAMkD,WAAW,GAClCS,EAAiBD,EAAaR,WAAW,GAIzCU,GAAY,CAGhB,IAAKzQ,EAAOK,MAAM4I,GAAYW,aAAc,EAExCuF,EAAWqB,EAAef,QAAQC,cAElCW,EAAYlR,MAAMa,OAAOyC,MAAME,OAAO+L,MAAMS,GAAUjL,KACtDuM,EAAYtR,MAAMa,OAAOyC,MAAME,OAAO+L,MAAMS,GAAUG,MACtDD,EAAYlQ,MAAMa,OAAOyC,MAAME,OAAO+L,MAAMS,GAAUE,WAOtD,IAHAgB,EAAYrQ,EAAOK,MAAM4I,GAAYmH,KAAKI,GAC1CC,EAAY5D,EAAM6D,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUK,oBAErDpK,EAAOK,MAAM4I,GAAY2H,SAAU,CAEnC,GAAIC,GAAS7Q,EAAOK,MAAM4I,GAAY2H,SAASP,EAK/C,KAAKQ,EACD,OAMZP,GACI7L,KAASwE,EACToG,OAASA,EACTnL,KAASmM,GAIbC,EAAOhB,MAAQmB,EAEfzQ,EAAOyC,MAAMC,WAAWyG,KAAKmH,IAI1B7P,QRitCL,SAAShB,EAAQD,GAEtB,YSr2CDC,GAAOD,QAAW,SAAUkB,GAExB,GAAIV,GAASb,MAAMa,MAMnBU,GAAQoQ,YAAc,KAMtBpQ,EAAQqQ,uBAAyB,KAKjCrQ,EAAQsQ,KAAO,WAEXhR,EAAOI,KAAKoD,IAAI,cAKhBxD,EAAOyC,MAAMqN,KAAO9P,EAAO0B,MAAMc,SAASgN,WAO9C9O,EAAQuQ,eAAiB,WAErB,GACIC,GADAC,EAAYxM,OAAOyM,cAGvB,IAA6B,OAAzBD,EAAUE,WAEV,MAAO,KAcX,IARIH,EAFCC,EAAUE,WAAW5K,UAAYzG,EAAOI,KAAKgF,UAAUC,IAE9C8L,EAAUE,WAIVF,EAAUG,UAAUC,eAI5BvR,EAAOgB,OAAOwQ,kBAAkBN,GAAW,CAK7C,IAFA,GAAIO,GAASP,EAAQjM,WAEdwM,IAAWzR,EAAOgB,OAAOwQ,kBAAkBC,IAE9CA,EAASA,EAAOxM,UAIpBiM,GAAUO,EAId,MAAIP,IAAWlR,EAAO0B,MAAMc,SAEjB0O,EAIJ,MAOXxQ,EAAQgR,UAAY,WAEhB1R,EAAOU,QAAQoQ,YAAYJ,UAAUvE,IAAInM,EAAOM,GAAGyJ,UAAUI,oBAOjEzJ,EAAQiR,UAAY,WAEZ3R,EAAOU,QAAQoQ,aAEf9Q,EAAOU,QAAQoQ,YAAYJ,UAAUkB,OAAO5R,EAAOM,GAAGyJ,UAAUI,oBAYxEzJ,EAAQmR,mBAAqB,SAAUC,GAQnC,GANK9R,EAAOI,KAAKmG,UAAUuL,KAEvBA,EAAOA,EAAK7M,YAIZ6M,IAAS9R,EAAO0B,MAAMc,UAAYsP,IAAS1N,SAAS2N,KAEpD,MAAO,KAIP,OAAOD,EAAKpB,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUC,kBAE/C8H,EAAOA,EAAK7M,UAIhB,OAAO6M,IAWfpR,EAAQiN,mBAAqB,SAAUqE,GAGnChS,EAAOU,QAAQiR,YAEVK,IAMLtL,KAAKoK,YAAcpK,KAAKmL,mBAAmBG,KAc/CtR,EAAQuR,aAAe,SAAUC,EAAaC,GAE1C,IAAKD,IAAgBC,EAGjB,WADAnS,GAAOI,KAAKoD,IAAI,8BAMpB,OAAO0O,EAAYxB,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUC,kBAEtDkI,EAAcA,EAAYjN,UAQ1BiN,GAAYxB,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUK,qBAEnD+H,EAASzB,UAAUvE,IAAInM,EAAOM,GAAGyJ,UAAUK,oBAI3C8H,EAAYxB,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUM,oBAEnD8H,EAASzB,UAAUvE,IAAInM,EAAOM,GAAGyJ,UAAUM,mBAO/C8H,EAAS1C,QAAQJ,OAAS6C,EAAYzC,QAAQJ,OAG9CrP,EAAO0B,MAAMc,SAAS4P,aAAaD,EAAUD,GAK7ClS,EAAOU,QAAQiN,mBAAmBwE,GAKlCnS,EAAOM,GAAGsM,iBAAiBuF,GAK3BnS,EAAOM,GAAG+C,cAgBd3C,EAAQgN,YAAc,SAAWuB,EAAWoD,GAExC,GAAIC,GAAkBtS,EAAOU,QAAQoQ,YACjCyB,EAAkBtD,EAAUpC,MAC5B2F,EAAkBvD,EAAUxK,KAC5B6K,EAAkBL,EAAUK,MAC5BD,EAAkBJ,EAAUI,OAC5BO,EAAkBX,EAAUU,UAE5BwC,EAAWnS,EAAOU,QAAQ+R,gBAAgBF,EAAiBC,EAAW5C,EAAaP,EA2CvF,IAzCIC,KAAU,GAEV6C,EAASzB,UAAUvE,IAAInM,EAAOM,GAAGyJ,UAAUK,oBAI3CiF,GAEA8C,EAASzB,UAAUvE,IAAInM,EAAOM,GAAGyJ,UAAUM,mBAI3CiI,EAEAtS,EAAOI,KAAK0E,YAAYwN,EAAcH,GAOtCnS,EAAO0B,MAAMc,SAASoG,YAAYuJ,GAOtCnS,EAAOM,GAAGsM,iBAAiBuF,GAK3BnS,EAAOU,QAAQiN,mBAAmBwE,GAKlCnS,EAAOM,GAAG+C,aAGLgP,EAAiB,CAKlB,GAAIK,GAAoB1S,EAAOc,MAAM6R,yBAA0B,CAG/D,IAAID,IAAqB,EAAI,CAGzB,GAAIE,GAAkBT,EAASU,cAAc,qBACzCC,EAAkB1O,SAAS2O,eAAe,GAE9CH,GAAgBhK,YAAYkK,GAC5B9S,EAAOc,MAAMkS,IAAIJ,EAAiB,EAAG,GAErC5S,EAAOW,QAAQsS,OACfjT,EAAOW,QAAQuS,qBAGZ,CAEH,GAAIR,IAAsB1S,EAAOyC,MAAMG,OAAOiE,OAAS,EACnD,MAGJlC,QAAOwO,WAAW,WAGdnT,EAAOc,MAAMsS,eAAeV,GAC5B1S,EAAOW,QAAQsS,OACfjT,EAAOW,QAAQgH,QAEhB,KAUXjH,EAAQqQ,wBAAyB,GAWrCrQ,EAAQ2S,YAAc,SAAUC,EAAgBnB,EAAUjH,GAEtDA,EAAOA,GAAQlL,EAAOU,QAAQoQ,YAAYrB,QAAQvE,IAClD,IAAIqI,GAAmBvT,EAAOU,QAAQ+R,gBAAgBN,EAAUjH,EAGhElL,GAAOU,QAAQuR,aAAaqB,EAAgBC,GAG5CvT,EAAOM,GAAG+C,cAcd3C,EAAQ8S,+BAAiC,SAAU3G,EAAOsC,GAMtD,GACIN,GACAiD,EACA2B,EAHAC,EAAc7G,EAAMkD,UAKxB,KAAIlB,EAAQ,EAAGA,EAAQ6E,EAAY7M,OAAQgI,IAEvCiD,EAAO4B,EAAY7E,GAEfiD,EAAKrL,UAAYzG,EAAOI,KAAKgF,UAAUE,OAEvCmO,EAAO3B,EAAK6B,YAAYC,OAKX,KAATH,IAEA5G,EAAMgH,YAAY/B,GAClB3C,KAQZ,IAAgC,IAA5BtC,EAAMkD,WAAWlJ,OAEjB,MAAOzC,UAAS2O,eAAe,GAK9B5D,GAAW,IACZA,EAAW,EAEf,IAAI2E,IAAmB,CAUvB,KAPiB,IAAb3E,IAEA2E,GAAmB,EACnB3E,EAAW,GAIPA,GAKAtC,EAFCiH,EAEOjH,EAAMkD,WAAW,GAIjBlD,EAAMkD,WAAWZ,EAAW,GAInCtC,EAAMpG,UAAYzG,EAAOI,KAAKgF,UAAUC,IAEzC8J,EAAWtC,EAAMkD,WAAWlJ,OAErBgG,EAAMpG,UAAYzG,EAAOI,KAAKgF,UAAUE,OAE/C6J,EAAW,EAMnB,OAAOtC,IAOXnM,EAAQ+R,gBAAkB,SAAU5F,EAAO3B,EAAM0E,EAAaP,GAE1D,GAAI8C,GAAenS,EAAOa,KAAKiR,KAAK,MAAO9R,EAAOM,GAAGyJ,UAAUC,oBAC3DuG,EAAevQ,EAAOa,KAAKiR,KAAK,MAAO9R,EAAOM,GAAGyJ,UAAUE,iBAa/D,OAXAsG,GAAa3H,YAAYiE,GACzBsF,EAASvJ,YAAY2H,GAEjBX,GAEAW,EAAaG,UAAUvE,IAAInM,EAAOM,GAAGyJ,UAAUG,iBAInDiI,EAAS1C,QAAQvE,KAASA,EAC1BiH,EAAS1C,QAAQJ,OAASA,GAAU,GAC7B8C,GAOXzR,EAAQqT,SAAW,WAEf,GAAI5C,GAAYxM,OAAOyM,eAAe4C,WAAW,EAEjD,OAAO7C,IASXzQ,EAAQuT,WAAa,SAAUC,GAE3B,GAIIC,GACAC,EACAC,EACAC,EAPAnD,EAAiBxM,OAAOyM,eACxBC,EAAiBF,EAAUE,WAC3BkD,EAAiBlD,EAAWsC,YAC5Ba,EAAiBrD,EAAUsD,aAM3BC,EAAe1U,EAAOU,QAAQoQ,YAAY+B,cAAc,oBAG5DsB,GAAsBI,EAAeI,UAAU,EAAGH,GAClDH,EAAsBE,EAAeI,UAAUH,GAE/CJ,EAAsBhQ,SAAS2O,eAAeoB,GAE1CE,IAEAC,EAAsBlQ,SAAS2O,eAAesB,GAIlD,IAAIO,MACAC,KACAC,GAAiB,CAEjBR,IAEAO,EAAW1L,KAAKmL,EAIpB,KAAM,GAAWS,GAAPC,EAAI,EAAaD,EAAQL,EAAa3E,WAAWiF,GAAKA,IAEvDD,GAAS1D,EAEJyD,EAMFD,EAAW1L,KAAK4L,GAJhBH,EAAezL,KAAK4L,GAUxBD,GAAiB,CAOzB9U,GAAOyC,MAAMG,OAAOsR,GAAY1E,UAAY,EAK5C,IAAIyF,GAAuBL,EAAe/N,MAE1C,KAAImO,EAAI,EAAGA,EAAIC,EAAsBD,IAEjChV,EAAOyC,MAAMG,OAAOsR,GAAYtL,YAAYgM,EAAeI,GAI/DhV,GAAOyC,MAAMG,OAAOsR,GAAYtL,YAAYwL,EAK5C,IAAIc,GAAmBL,EAAWhO,OAC9BsO,EAAmB/Q,SAASkE,cAAc,MAE9C,KAAI0M,EAAI,EAAGA,EAAIE,EAAkBF,IAE7BG,EAAQvM,YAAYiM,EAAWG,GAInCG,GAAUA,EAAQ3F,SAGlB,IAAI4F,GAAiBpV,EAAOsB,SAASG,kBAKrCzB,GAAOU,QAAQgN,aACXjJ,KAAQ2Q,EACRvI,MAAQ7M,EAAOK,MAAM+U,GAAgB7J,QACjCkI,KAAO0B,MAEZ,IAQPzU,EAAQ2U,YAAc,SAAU3C,EAAmB4C,GAG/C,GAA0B,IAAtB5C,EAAJ,CAMA,GAAI6C,GACAC,EAAsBxV,EAAOyC,MAAMG,OAAO8P,GAAmBlD,SAQ7D+F,GANCD,EAMatV,EAAOyC,MAAMG,OAAO0S,GAJpBtV,EAAOyC,MAAMG,OAAO8P,EAAoB,GAQ1D6C,EAAY/F,WAAagG,IAU7B9U,EAAQW,MAAQ,SAAUoU,GAEtB,GAAIC,GAAc1V,EAAOU,QAAQoQ,YAC7B5F,EAAcwK,EAAYjG,QAAQvE,IAElClL,GAAOK,MAAM6K,GAAMyK,eAEnB3V,EAAOU,QAAQkV,SAAShW,KAAK8G,KAAM+O,EAAS1Q,QAI5C/E,EAAOU,QAAQmV,iBAAiBJ,EAASK,aAYjDpV,EAAQmV,iBAAmB,SAAUnU,GAEjC,GACIqU,GADAjE,EAAOpQ,EAAM,EAGZoQ,KAQDiE,EAFAjE,EAAKrL,UAAYzG,EAAOI,KAAKgF,UAAUE,KAE5BlB,SAAS2O,eAAejB,GAIxB1N,SAAS2O,eAAejB,EAAK6B,aAIxC3T,EAAOI,KAAKmG,UAAUuL,IAEtBA,EAAK7M,WAAWmN,aAAa2D,EAAUjE,KAa/CpR,EAAQkV,SAAW,SAAU7Q,GAEzB,GAAKA,EAAL,CAMA,GAAI+M,GAAO/M,EAAO,EAElB,IAAK+M,IAULpL,KAAKsP,aAKDlE,EAAKrL,UAAYzG,EAAOI,KAAKgF,UAAUE,MAA3C,CASA,GAAI2Q,GAAUjW,EAAOiB,UAAUd,KAAKH,EAAOkW,UAAUC,OAAOC,OACxDC,EAAQJ,EAAQI,MAAMtR,EAAOuR,WAE7BC,EAAMvW,EAAOa,KAAKiR,KAAK,UAAatC,UAAW6G,GAEnDvE,GAAK0E,YAAYD,EAAIxG,WAAW,OAYpCrP,EAAQ+V,WAAa,SAAU3E,GAM3B,IAFA,GAAI4E,IAAa,GAERA,GAAa,CAKlB,IAAMC,EAAkB7E,GAGpB,OAAO,CAIXA,GAAOA,EAAK7M,WAKP6M,EAAKpB,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUE,iBAE7CyM,GAAa,GAMrB,OAAO,EAQX,IAAIC,GAAoB,SAAU7E,GAO9B,IAFA,GAAI8E,GAAU9E,EAAK3M,YAEXyR,GAAU,CAEd,GAAIA,EAAQjD,YAAY9M,OAEpB,OAAO,CAIX+P,GAAUA,EAAQzR,YAItB,OAAO,EA2FX,OAjFAzE,GAAQmW,uBAAyB,SAAUC,GAEvC,GAEI9B,GACA+B,EAEAC,EACAlF,EANAlQ,EAAUwC,SAASkE,cAAc,OACjC2O,EAAa7S,SAASkE,cAAc,OAGpC4O,GAAoB,MAAO,IAW/B,KAHAtV,EAAQ4N,UAAYsH,EACpBC,EAAY3S,SAASkE,cAAc,KAE9B0M,EAAI,EAAGA,EAAIpT,EAAQmO,WAAWlJ,OAAQmO,IAEvClD,EAAOlQ,EAAQmO,WAAWiF,GAE1BgC,EAAaE,EAAiBC,QAAQrF,EAAKsF,WAAY,EAMlDJ,GAKID,EAAUhH,WAAWlJ,SAEtBoQ,EAAWrO,YAAYmO,EAAUM,WAAU,IAG3CN,EAAY,KACZA,EAAY3S,SAASkE,cAAc,MAIvC2O,EAAWrO,YAAYkJ,EAAKuF,WAAU,MAKtCN,EAAUnO,YAAYkJ,EAAKuF,WAAU,IAGhCrC,GAAKpT,EAAQmO,WAAWlJ,OAAS,GAElCoQ,EAAWrO,YAAYmO,EAAUM,WAAU,IAQvD,OAAOJ,GAAWzH,WAStB9O,EAAQ4W,kBAAoB,SAAUxF,GAElC,KAAOA,GAAgC,QAAxBA,EAAKyF,iBAEhBzF,EAAOA,EAAK7M,UAIhB,OAAO6M,IAIJpR,QToxCL,SAASjB,EAAQD,EAASH,GAE/B,YUloEDI,GAAOD,QAAW,SAAUmB,GAExB,GAAIX,GAASb,MAAMa,MAwGnB,OAtGAW,GAAQW,SAAWjC,EAAQ,GAC3BsB,EAAQqM,OAAW3N,EAAQ,IAC3BsB,EAAQqB,QAAW3C,EAAQ,IAK3BsB,EAAQ6W,qBAAuB,GAE/B7W,EAAQ8W,cAAgB,GAExB9W,EAAQ+W,QAAS,EAEjB/W,EAAQ0M,QAAU,KAKlB1M,EAAQgH,KAAO,WAEP3H,EAAOmE,cAMXnE,EAAO0B,MAAMf,QAAQ+P,UAAUvE,IAAI,UACnCzF,KAAKgR,QAAS,IAOlB/W,EAAQgX,MAAQ,WAEZ3X,EAAO0B,MAAMf,QAAQ+P,UAAUkB,OAAO,UAEtCjR,EAAQ+W,QAAU,EAClB/W,EAAQ0M,QAAU,IAElB,KAAK,GAAIX,KAAU1M,GAAO0B,MAAMa,eAE5BvC,EAAO0B,MAAMa,eAAemK,GAAQgE,UAAUkB,OAAO,WAKzD5R,GAAOW,QAAQqB,QAAQ2V,QACvB3X,EAAOW,QAAQW,SAASqW,SAI5BhX,EAAQiX,OAAS,WAEPlR,KAAKgR,OAMPhR,KAAKiR,QAJLjR,KAAKiB,QAUbhH,EAAQkX,eAAiB,WAErB7X,EAAO0B,MAAMO,WAAWyO,UAAUvE,IAAI,SAI1CxL,EAAQuS,eAAiB,WAErBlT,EAAO0B,MAAMO,WAAWyO,UAAUkB,OAAO,SAO7CjR,EAAQsS,KAAO,WAKX,GAFAjT,EAAOW,QAAQqB,QAAQ2V,QAElB3X,EAAOU,QAAQoQ,YAApB,CAMA,GAAIgH,GAAiB9X,EAAOU,QAAQoQ,YAAYiH,UAAa/X,EAAOW,QAAQ6W,qBAAuB,EAAKxX,EAAOW,QAAQ8W,aAEvHzX,GAAO0B,MAAMf,QAAQqX,MAAMC,UAA3B,kBAAyDC,KAAKC,MAAML,GAApE,SAGA9X,EAAOW,QAAQW,SAAS8W,sBAIrBzX,QV0oEL,SAASlB,EAAQD,GAEtB,YW5vEDC,GAAOD,QAAW,SAAU8B,GAExB,GAAItB,GAASb,MAAMa,MA8RnB,OA5RAsB,GAASoW,QAAS,EAElBpW,EAAS+W,QAAU,KACnB/W,EAASS,QAAU,KAEnBT,EAASgO,MAAQ,KAKjBhO,EAASqG,KAAO,SAAU2Q,GAMtB,GAAKtY,EAAOK,MAAMiY,IAActY,EAAOK,MAAMiY,GAAUC,aAKhD,CAKH,GAAIC,GAAgBxY,EAAOK,MAAMiY,GAAUC,cAE3CvY,GAAO0B,MAAMW,eAAeuG,YAAY4P,OAVxCxY,GAAOI,KAAKoD,IAAZ,WAA2B8U,EAA3B,oBAAwD,OAe5DtY,GAAO0B,MAAMU,cAAcsO,UAAUvE,IAAI,UACzCnM,EAAOW,QAAQW,SAASwJ,qBACxBpE,KAAKgR,QAAS,GAOlBpW,EAASqW,MAAQ,WAEb3X,EAAO0B,MAAMU,cAAcsO,UAAUkB,OAAO,UAC5C5R,EAAO0B,MAAMW,eAAemN,UAAY,GAExC9I,KAAKgR,QAAS,GAOlBpW,EAASsW,OAAS,SAAWU,GAEnB5R,KAAKgR,OAOPhR,KAAKiR,SALLjR,KAAKiB,KAAK2Q,GACVtY,EAAOkB,QAAQuX,eAAezY,EAAOU,QAAQoQ,eAarDxP,EAASwJ,mBAAqB,WAG1B,GAAI4N,GACAC,CAGJ3Y,GAAO0B,MAAMY,gBAAgBkN,UAAY,GAIzCkJ,EAAkB1Y,EAAOW,QAAQW,SAASsX,sBAC1CD,EAAkB3Y,EAAOW,QAAQW,SAASuX,kBAS1C7Y,EAAO0B,MAAMY,gBAAgBsG,YAAY+P,GAMzC3Y,EAAO0B,MAAMY,gBAAgBsG,YAAY8P,IAa7CpX,EAASsX,oBAAsB,WAE3B,GACIP,GACAnU,EAFA4U,EAAsB9Y,EAAOW,QAAQW,SAASwX,qBAqBlD,OATI5U,GARC4U,GASGtJ,UAAY,yDANZA,UAAY,oDAWpB6I,EAAUrY,EAAOa,KAAKiR,KAAK,MAAO9R,EAAOM,GAAGyJ,UAAUO,cAAepG,GACrElE,EAAOmB,UAAUgL,IAAIkM,EAAS,QAASrY,EAAOW,QAAQW,SAASyX,gBAAgB,GAExEV,GAOX/W,EAASyX,eAAiB,WAEtB,GAAIjI,GAAc9Q,EAAOU,QAAQoQ,WAEjCA,GAAYJ,UAAUkH,OAAO5X,EAAOM,GAAGyJ,UAAUK,oBAEjDpK,EAAOW,QAAQW,SAASqW,SAI5BrW,EAASwX,oBAAsB,WAE3B,GAAIpE,GAAe1U,EAAOU,QAAQoQ,WAElC,SAAI4D,GAEOA,EAAahE,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUK,qBAUnE9I,EAASuX,gBAAkB,WAEvB,GAAIG,GAAgBhZ,EAAOa,KAAKiR,KAAK,MAAO,oDACxCmH,EAASjZ,EAAOa,KAAKiR,KAAK,IAAK,+BAC/BzC,EAASrP,EAAOa,KAAKiR,KAAK,QAAS,6BAA+BoH,YAAa,SAYnF,OAVAlZ,GAAOmB,UAAUgL,IAAIkD,EAAQ,UAAWrP,EAAOkB,QAAQiY,sBACvDnZ,EAAOmB,UAAUgL,IAAIkD,EAAQ,QAASrP,EAAOkB,QAAQkY,oBACrDpZ,EAAOmB,UAAUgL,IAAIkD,EAAQ,QAASrP,EAAOkB,QAAQmY,eACrDrZ,EAAOmB,UAAUgL,IAAIkD,EAAQ,OAAQrP,EAAOkB,QAAQmY,eAEpDL,EAAcpQ,YAAYqQ,GAC1BD,EAAcpQ,YAAYyG,GAE1BrP,EAAOkB,QAAQ4M,MAAQuB,EAEhB2J,GAOX1X,EAASqJ,sBAAwB,WAE7B,GAAI2O,GAAsBtZ,EAAOa,KAAKiR,KAAK,OAAQ,6BAC/CyH,EAAgBvZ,EAAOa,KAAKiR,KAAK,OAAQ,8BAAgCtC,UAAY,kCACrFgK,EAAgBxZ,EAAOa,KAAKiR,KAAK,MAAO,sCACxC2H,EAAgBzZ,EAAOa,KAAKiR,KAAK,MAAO,8BAAgC6B,YAAc,iBACtF+F,EAAgB1Z,EAAOa,KAAKiR,KAAK,MAAO,6BAA+B6B,YAAc,UAkBzF,OAhBA3T,GAAOmB,UAAUgL,IAAIoN,EAAe,QAASvZ,EAAOW,QAAQW,SAASqY,qBAAqB,GAE1F3Z,EAAOmB,UAAUgL,IAAIsN,EAAe,QAASzZ,EAAOW,QAAQW,SAASsY,wBAAwB,GAE7F5Z,EAAOmB,UAAUgL,IAAIuN,EAAc,QAAS1Z,EAAOW,QAAQW,SAASuY,uBAAuB,GAE3FL,EAAc5Q,YAAY6Q,GAC1BD,EAAc5Q,YAAY8Q,GAE1BJ,EAAmB1Q,YAAY2Q,GAC/BD,EAAmB1Q,YAAY4Q,GAG/BxZ,EAAOW,QAAQW,SAAS+W,QAAUkB,EAClCvZ,EAAOW,QAAQW,SAASS,QAAUyX,EAE3BF,GAIXhY,EAASqY,oBAAsB,WAE3B,GAAIG,GAAS9Z,EAAOW,QAAQW,SAASS,OAEjC+X,GAAOpJ,UAAUC,SAAS,UAE1B3Q,EAAOW,QAAQW,SAAS8W,oBAIxBpY,EAAOW,QAAQW,SAASyY,oBAI5B/Z,EAAOW,QAAQqB,QAAQ2V,QACvB3X,EAAOW,QAAQW,SAASqW,SAI5BrW,EAASuY,sBAAwB,WAE7B7Z,EAAOW,QAAQW,SAASS,QAAQ2O,UAAUkB,OAAO,WAIrDtQ,EAASsY,uBAAyB,WAE9B,GACII,GADAtF,EAAe1U,EAAOU,QAAQoQ,WAGlC4D,GAAa9C,SAEboI,EAAwBha,EAAO0B,MAAMc,SAASuN,WAAWlJ,OAK3B,IAA1BmT,IAGAha,EAAOU,QAAQoQ,YAAc,KAG7B9Q,EAAOM,GAAGgN,mBAIdtN,EAAOM,GAAG+C,aAEVrD,EAAOW,QAAQgX,SAInBrW,EAASyY,kBAAoB,WAEzB/Z,EAAOW,QAAQW,SAASS,QAAQ2O,UAAUvE,IAAI,WAIlD7K,EAAS8W,kBAAoB,WAEzBpY,EAAOW,QAAQW,SAASS,QAAQ2O,UAAUkB,OAAO,WAI9CtQ,QX8uEL,SAAS7B,EAAQD,GAEtB,YY5gFDC,GAAOD,QAAW,SAAUwN,GAExB,GAAIhN,GAASb,MAAMa,MAEnBgN,GAAOiN,cAAgB,KACvBjN,EAAOkN,cAAgB,KACvBlN,EAAOmN,eAAiB,KAMxBnN,EAAOoN,gBAAkB,KAOzBpN,EAAOC,KAAO,WAEV,GAEI/D,GAFA4H,EAAc9Q,EAAOU,QAAQoQ,YAC7B5F,EAAO4F,EAAYrB,QAAQvE,IAQ/B,IAFAhC,EAASlJ,EAAOK,MAAM6K,GAEjBhC,EAAOmR,kBAAZ,CAGA,GAAIC,GAAetN,EAAOuN,mBACtB5Z,EAAeX,EAAO0B,MAAMG,cAAcD,OAE1C0Y,GAAazT,OAAS,IAGtB7G,EAAOW,QAAQqM,OAAOiG,OAGtBtS,EAAQ+P,UAAUvE,IAAI,UAGtBnM,EAAOW,QAAQqM,OAAOwN,iBAW9BxN,EAAO2K,MAAQ,WAEX,GAAIhX,GAAUX,EAAO0B,MAAMG,cAAcD,OAEzCjB,GAAQ+P,UAAUkB,OAAO,WAS7B5E,EAAOiG,KAAO,WAELvM,KAAKyT,iBAENzT,KAAKyT,eAAiBzT,KAAK+T,oBAI/B,IAGIC,GACAC,EAJAC,EAAkBlU,KAAKmU,qBACvBpD,EAAkB,EAClB9W,EAAkBX,EAAO0B,MAAMG,cAAcD,OAIpB,KAAzBjB,EAAQma,eAERrD,EAAgB,IAIpBiD,EAAiBE,EAAOG,EAAIrU,KAAKyT,eAAea,KAChDL,EAAiBC,EAAOK,EAAItW,OAAOuW,QAAUxU,KAAKyT,eAAegB,IAAM1D,EAAgB9W,EAAQma,aAE/Fna,EAAQqX,MAAMC,UAAd,eAAyCC,KAAKC,MAAMuC,GAApD,OAA0ExC,KAAKC,MAAMwC,GAArF,SAGA3a,EAAOW,QAAQqM,OAAOoO,eACtBpb,EAAOW,QAAQqM,OAAOqO,eAU1BrO,EAAOa,YAAc,SAAUD,EAAOnJ,GAMlC,OAAQA,GACJ,IAAK,aAAezE,EAAOW,QAAQqM,OAAOsO,iBAAiB1N,EAAOnJ,EAAO,MACzE,SAAoBzE,EAAOW,QAAQqM,OAAOuO,kBAAkB9W,GAOhEzE,EAAO0B,MAAMG,cAAcC,QAAQiO,WAAWyL,QAAQxb,EAAOW,QAAQqM,OAAOyO,aAShFzO,EAAOyN,kBAAoB,WAEvB,GAAI7Y,GAAU5B,EAAO0B,MAAME,QACvB8Z,EAAUhV,KAAKiV,UAAU/Z,EAG7B,OADA8E,MAAKyT,eAAiBuB,EACfA,GAYX1O,EAAO2O,UAAY,SAAWnV,GAK1B,IAHA,GAAIoV,GAAK,EACLC,EAAK,EAEFrV,IAAOsV,MAAOtV,EAAGuV,cAAiBD,MAAOtV,EAAGuR,YAE/C6D,GAAOpV,EAAGuV,WAAavV,EAAGwV,WAC1BH,GAAOrV,EAAGuR,UAAYvR,EAAGyV,UACzBzV,EAAKA,EAAG0V,YAGZ,QAASf,IAAKU,EAAIb,KAAMY,IAU5B5O,EAAO6N,mBAAqB,WAExB,GAA8BsB,GAA1BC,EAAMhY,SAAS+M,UACf4J,EAAI,EAAGE,EAAI,CAEf,IAAImB,EAEgB,WAAZA,EAAI3X,OAEJ0X,EAAQC,EAAIC,cACZF,EAAMG,UAAS,GACfvB,EAAIoB,EAAMI,aACVtB,EAAIkB,EAAMK,iBAIX,IAAI7X,OAAOyM,eAEdgL,EAAMzX,OAAOyM,eAETgL,EAAIK,aAEJN,EAAQC,EAAIpI,WAAW,GAAG0I,aACtBP,EAAMQ,iBAAgB,CAEtBR,EAAMG,UAAS,EACf,IAAIM,GAAOT,EAAMQ,iBAAiB,EAElC,KAAKC,EAED,MAIJ7B,GAAI6B,EAAK5B,KACTC,EAAI2B,EAAKzB,IAOrB,OAASJ,EAAGA,EAAGE,EAAGA,IAUtBjO,EAAOuN,iBAAmB,WAEtB,GAAID,GAAe,EASnB,OANI3V,QAAOyM,eAEPkJ,EAAe3V,OAAOyM,eAAeyL,YAIlCvC,GAKXtN,EAAOwN,YAAc,WAEjB,GAAI1Y,GAAU9B,EAAO0B,MAAMG,cAAcC,OAEzCA,GAAQ4O,UAAUvE,IAAI,UAEtBnM,EAAOW,QAAQqM,OAAOiN,eAAgB,EAGtCja,EAAO0B,MAAMG,cAAcC,QAAQiO,WAAWyL,QAAQxb,EAAOW,QAAQqM,OAAOyO,aAKhFzO,EAAOoO,aAAe,WAElB,GAAItZ,GAAU9B,EAAO0B,MAAMG,cAAcC,OAEzCA,GAAQ4O,UAAUkB,OAAO,UAEzB5R,EAAOW,QAAQqM,OAAOiN,eAAgB,GAK1CjN,EAAO8P,YAAc,WAEjB,GAAIhD,GAAS9Z,EAAO0B,MAAMG,cAAcE,OAExC+X,GAAOpJ,UAAUvE,IAAI,UAErBnM,EAAOW,QAAQqM,OAAOkN,eAAgB,GAK1ClN,EAAOqO,YAAc,WAEjB,GAAIvB,GAAS9Z,EAAO0B,MAAMG,cAAcE,OAExC+X,GAAOtK,UAAY,GACnBsK,EAAOpJ,UAAUkB,OAAO,UACxB5R,EAAOW,QAAQqM,OAAOkN,eAAgB,EAQ1C,IAAI6C,GAAmC,SAAUnP,GAE7C,GAAIA,EAAMoP,SAAWhd,EAAOI,KAAKoF,KAAKG,MAAtC,CAMA,GAAIsX,GAAkBjd,EAAOU,QAAQoQ,YACjCsJ,EAAkBpa,EAAOW,QAAQqM,OAAOoN,eAE5Cpa,GAAOW,QAAQqM,OAAOkQ,iBAAiBD,EAAU7C,GACjDpa,EAAOW,QAAQqM,OAAOmQ,UAAUzW,KAAK0W,OAKrCxP,EAAMyP,iBACNzP,EAAM0P,2BAENtd,EAAOW,QAAQqM,OAAOuQ,cAgR1B,OA3QAvQ,GAAOsO,iBAAmB,SAAU1N,GAEhC,GAAI4P,GAAW9W,KAAK+W,eAEhBR,EAAkBjd,EAAOU,QAAQoQ,YACjCsJ,EAAkBpa,EAAOW,QAAQqM,OAAO0Q,cAAcT,EAK1D,IAFAjd,EAAOW,QAAQqM,OAAOoN,gBAAkBA,EAEpCoD,EASAxd,EAAOW,QAAQqM,OAAOkQ,iBAAiBD,EAAU7C,GAEjDpa,EAAOW,QAAQqM,OAAOuO,kBAAkB,cAErC,CAGH,GAAIzB,GAAS9Z,EAAOa,KAAK8c,cAEzB3d,GAAO0B,MAAMG,cAAcE,QAAQ6G,YAAYkR,GAE/C9Z,EAAOW,QAAQqM,OAAOoO,eACtBpb,EAAOW,QAAQqM,OAAO8P,cAOtBhD,EAAO8D,QACPhQ,EAAMyP,iBAGNrd,EAAOmB,UAAUgL,IAAI2N,EAAQ,UAAWiD,GAAkC,KAMlF/P,EAAOyQ,aAAe,WAElB,GAAID,IAAW,CAcf,OAZAxd,GAAO0B,MAAMG,cAAcC,QAAQiO,WAAWyL,QAAQ,SAAUtQ,GAE5D,GAAI2S,GAAW3S,EAAKuE,QAAQhL,IAEZ,SAAZoZ,GAAsB3S,EAAKwF,UAAUC,SAAS,kBAE9C6M,GAAW,KAMZA,GAKXxQ,EAAOuO,kBAAoB,SAAU9W,GAEjCL,SAAS0Z,YAAYrZ,GAAM,EAAO,OAWtCuI,EAAOmQ,UAAY,SAAUpW,GAEzB3C,SAAS0Z,YAAY,cAAc,EAAO/W,GAG1C/G,EAAOW,QAAQqM,OAAOqO,eAS1BrO,EAAO0Q,cAAgB,SAAUK,GAE7B,GAEIlb,GAFAsZ,EAAQxX,OAAOyM,eAAe4C,WAAW,GACzCgK,EAAoB7B,EAAMO,YAQ9B,OALAsB,GAAkBC,mBAAmBF,GACrCC,EAAkBE,OAAO/B,EAAMgC,eAAgBhC,EAAMiC,aAErDvb,EAAQmb,EAAkBnB,WAAWhW,QAGjChE,MAAOA,EACPwb,IAAKxb,EAAQsZ,EAAMU,WAAWhW,SAatCmG,EAAOkQ,iBAAmB,SAAUa,EAAaO,GAE7C,GAAInC,GAAY/X,SAASiY,cACrBkC,EAAY,CAEhBpC,GAAMqC,SAAST,EAAa,GAC5B5B,EAAMG,UAAS,EAQf,KANA,GACIxK,GAGA2M,EAJAC,GAAcX,GAEdY,GAAa,EACbC,GAAO,GAGHA,IAAS9M,EAAO4M,EAAUG,QAE9B,GAAqB,GAAjB/M,EAAKrL,SAELgY,EAAgBF,EAAYzM,EAAKjL,QAE5B8X,GAAcL,EAASzb,OAAS0b,GAAaD,EAASzb,OAAS4b,IAEhEtC,EAAMqC,SAAS1M,EAAMwM,EAASzb,MAAQ0b,GACtCI,GAAa,GAGbA,GAAcL,EAASD,KAAOE,GAAaD,EAASD,KAAOI,IAE3DtC,EAAM+B,OAAOpM,EAAMwM,EAASD,IAAME,GAClCK,GAAO,GAGXL,EAAYE,MAMZ,KAFA,GAAIzJ,GAAIlD,EAAK/B,WAAWlJ,OAEjBmO,KAEH0J,EAAUvV,KAAK2I,EAAK/B,WAAWiF,GAQ3C,IAAIoH,GAAMzX,OAAOyM,cAEjBgL,GAAI0C,kBACJ1C,EAAI2C,SAAS5C,IASjBnP,EAAOuQ,WAAa,WAEhB,GAAIpM,GAAYxM,OAAOyM,cAEvBD,GAAU2N,mBASd9R,EAAOyO,WAAa,SAAUvQ,GAE1B,GAAI2S,GAAW3S,EAAKuE,QAAQhL,IAExBL,UAAS4a,kBAAkBnB,GAE3B7d,EAAOW,QAAQqM,OAAOiS,qBAAqB/T,GAI3ClL,EAAOW,QAAQqM,OAAOkS,uBAAuBhU,EAQjD,IAAIiG,GAAYxM,OAAOyM,eACnB+N,EAAMhO,EAAUE,WAAWpM,UAEZ,MAAfka,EAAI/H,SAA8B,QAAZyG,GAEtB7d,EAAOW,QAAQqM,OAAOiS,qBAAqB/T,IAWnD8B,EAAOiS,qBAAuB,SAAUvS,GAKpC,GAHAA,EAAOgE,UAAUvE,IAAI,gBAGM,QAAvBO,EAAO+C,QAAQhL,KAAgB,CAE/B,GAAIkH,GAAOe,EAAOqD,WAAW,EAE7BpE,GAAK+E,UAAUkB,OAAO,gBACtBjG,EAAK+E,UAAUvE,IAAI,oBAW3Ba,EAAOkS,uBAAyB,SAAUxS,GAKtC,GAHAA,EAAOgE,UAAUkB,OAAO,gBAGG,QAAvBlF,EAAO+C,QAAQhL,KAAgB,CAE/B,GAAIkH,GAAOe,EAAOqD,WAAW,EAE7BpE,GAAK+E,UAAUkB,OAAO,kBACtBjG,EAAK+E,UAAUvE,IAAI,kBAOpBa,QZ2+EL,SAASvN,EAAQD,GAEtB,YaljGDC,GAAOD,QAAW,SAAUwC,GAExB,GAAIhC,GAASb,MAAMa,MAwKnB,OAtKAgC,GAAQ0V,QAAS,EAGjB1V,EAAQ2F,KAAO,WAGP3H,EAAOW,QAAQW,SAASoW,QAExB1X,EAAOW,QAAQW,SAASqW,QAK5B3X,EAAO0B,MAAMM,QAAQ0O,UAAUvE,IAAI,UAGnCnM,EAAO0B,MAAMO,WAAWyO,UAAUvE,IAAI,WAGtCnM,EAAOW,QAAQqB,QAAQ0V,QAAS,GAKpC1V,EAAQ2V,MAAQ,WAGZ3X,EAAO0B,MAAMM,QAAQ0O,UAAUkB,OAAO,UAGtC5R,EAAO0B,MAAMO,WAAWyO,UAAUkB,OAAO,WAGzC5R,EAAOW,QAAQqB,QAAQ0V,QAAS,EAEhC1X,EAAOW,QAAQ0M,QAAU,MAI7BrL,EAAQod,KAAO,WAEX,GAAIC,GAAcrf,EAAOW,QAAQ0M,QAC7BhN,EAAcuG,OAAOpB,KAAKxF,EAAOK,OACjCif,EAActf,EAAO0B,MAAMa,eAC3Bgd,EAAgB,EAChBC,SACAC,SACAvU,QAEJ,IAAMmU,EAoBF,IAHAE,GAAiBlf,EAAM8W,QAAQkI,GAAe,GAAKhf,EAAMwG,OACzD4Y,EAAcpf,EAAMkf,IAEZvf,EAAOK,MAAMof,GAAanU,kBAE9BiU,GAAiBA,EAAgB,GAAKlf,EAAMwG,OAC5C4Y,EAAcpf,EAAMkf,OApBxB,KAAIrU,IAAQlL,GAAOK,MAAO,CAEtB,GAAIL,EAAOK,MAAM6K,GAAMI,iBAEnB,KAIJiU,KAkBRC,EAAenf,EAAMkf,EAErB,KAAM,GAAI7S,KAAU4S,GAEhBA,EAAW5S,GAAQgE,UAAUkB,OAAO,WAIxC0N,GAAWE,GAAc9O,UAAUvE,IAAI,YACvCnM,EAAOW,QAAQ0M,QAAUmS,GAQ7Bxd,EAAQ6L,YAAc,SAAUD,GAK5B,GAII2E,GACAmN,EACAzQ,EANA0Q,GAAsB,QAAS,OAAQ,OAAQ,YAAa,UAAW,SACvEzU,EAAqBlL,EAAOK,MAAML,EAAOW,QAAQ0M,SACjDqI,EAAqB1V,EAAOU,QAAQoQ,YACpC4B,EAAqB1S,EAAOc,MAAMoT,UAMtC3B,GAAkBrH,EAAKK,SAGvB0D,GACIpC,MAAY0F,EACZ9N,KAAYyG,EAAKzG,KACjBkL,WAAY,GAIZ+F,GACAiK,EAAmBxI,QAAQzB,EAAYjG,QAAQvE,SAAU,GACtB,KAAnCwK,EAAY/B,YAAYC,OAIxB5T,EAAOU,QAAQ2S,YAAYqC,EAAanD,EAAiBrH,EAAKzG,OAK9DzE,EAAOU,QAAQgN,YAAYuB,GAG3ByD,KAKJgN,EAAiBxU,EAAKwU,eAElBA,GAA2C,kBAAlBA,IAEzBA,EAAe9f,KAAKgO,GAIxBjJ,OAAOwO,WAAW,WAGdnT,EAAOc,MAAM8e,WAAWlN,IAEzB,IAMH1S,EAAOU,QAAQiN,qBAKf3N,EAAOW,QAAQsS,QAIZjR,Qb8iGL,SAASvC,EAAQD,GAEtB,Yc5tGDC,GAAOD,QAAW,SAAUqgB,GAExB,GAAI7f,GAASb,MAAMa,MAEnB6f,GAAUzT,cAAgB,SAAUwB,GAEhC,OAAQA,EAAMoP,SACV,IAAKhd,GAAOI,KAAKoF,KAAKG,MAAQ3F,EAAOY,SAASkf,gBAAgBlS,KAKtEiS,EAAUxT,gBAAkB,SAAUuB,GAElC,OAAQA,EAAMoP,SACV,IAAKhd,GAAOI,KAAKoF,KAAKE,IAAQ1F,EAAOY,SAASmf,cAAcnS,EAA4B,MACxF,KAAK5N,GAAOI,KAAKoF,KAAKG,MAAQ3F,EAAOY,SAASof,8BAA8BpS,EAAY,MACxF,KAAK5N,GAAOI,KAAKoF,KAAKO,IAAQ/F,EAAOY,SAASqf,iBAAiBrS,EAAyB,MACxF,SAA6B5N,EAAOY,SAASsf,kBAAkBtS,KAKvEiS,EAAUvT,YAAc,SAAUsB,GAE9B,OAAQA,EAAMoP,SACV,IAAKhd,GAAOI,KAAKoF,KAAKU,GACtB,IAAKlG,GAAOI,KAAKoF,KAAKS,KACtB,IAAKjG,GAAOI,KAAKoF,KAAKY,MACtB,IAAKpG,GAAOI,KAAKoF,KAAKW,KAAQnG,EAAOY,SAASuf,gBAAgBvS,KAKtEiS,EAAUE,cAAgB,SAAUnS,GAGhC,GAAIhL,GAAS5C,EAAOU,QAAQoQ,YAAY5D,iBAAiB,mBACrDkT,GAAmB,EACnBC,GAAsBrgB,EAAOU,QAAQoQ,YAAY6C,YAAYC,MAEjEzG,OAAMrJ,UAAUsJ,IAAIxN,KAAKgD,EAAQ,SAAUkL,GAErB,YAAdA,EAAMrJ,MAAoC,QAAdqJ,EAAMrJ,OAElC2b,EAAiBA,IAAmBtS,EAAMsP,MAAMxJ,SAOxD,IAAI0M,GAAeD,GAAsBD,CAEpCE,KAMCtgB,EAAOW,QAAQ+W,QAEjB1X,EAAOW,QAAQgH,OAIf3H,EAAOW,QAAQ+W,SAAW1X,EAAOW,QAAQqB,QAAQ0V,OAEjD1X,EAAOW,QAAQqB,QAAQ2F,OAIvB3H,EAAOW,QAAQqB,QAAQod,OAI3BxR,EAAMyP,mBAOVwC,EAAUC,gBAAkB,WAEpB9f,EAAOU,QAAQqQ,yBAMf/Q,EAAOc,MAAMoT,YAAa,EAE1BlU,EAAOY,SAAS2f,wBAUxBV,EAAUG,8BAAgC,SAAUpS,GAEZ,QAAhCA,EAAM7I,OAAOwS,iBAGbvX,EAAOc,MAAM0f,uBAIjB,IAAI9N,GAA0B1S,EAAOc,MAAM6R,wBAA0B,EACjE+C,EAA0B1V,EAAOU,QAAQoQ,YACzC5F,EAA0BwK,EAAYjG,QAAQvE,KAC9CuV,EAA0BzgB,EAAOW,QAAQ+W,QACb1X,EAAOW,QAAQ0M,SACfO,EAAM7I,QAAU/E,EAAOyC,MAAMG,OAAO8P,GAGhEgO,EAAmB1gB,EAAOK,MAAM6K,GAAMwV,iBAGtCtL,EAAiBpV,EAAOsB,SAASG,kBAKrC,IAAKgf,EAcD,MAZA7S,GAAMyP,iBAENrd,EAAOW,QAAQqB,QAAQ6L,YAAYD,GAEnC5N,EAAOW,QAAQgX,QAKf/J,EAAM+S,sBACN/S,GAAM0P,0BAUV,IAAK1P,EAAMgT,UAAYF,EAInB,MAFA9S,GAAM+S,sBACN/S,GAAM0P,0BAKV,IAAIuD,GAAmBlc,OAAOyM,eAC1B0P,EAAsBD,EAAiBxP,WACvC0P,EAAsB/gB,EAAOc,MAAMqO,SAAS6R,WAC5CC,GAA4C,CAKhD,IAAKrT,EAAMgT,WAAaF,EAIpB,MAFA1gB,GAAOY,SAAS2f,oBAAoBvgB,EAAOU,QAAQgU,aAAc9G,OACjEA,GAAMyP,gBAeV,IALA4D,EAA4CH,GAAyE,QAAlDA,EAAoB7b,WAAWsS,gBAM9FuJ,EAAoBra,UAAYzG,EAAOI,KAAKgF,UAAUE,MACrD2b,GACAF,EAgBE,CAEH,GAAIG,GAAalhB,EAAOU,QAAQ+V,WAAWqK,EAEtCI,IAAcH,IAEfnT,EAAMyP,iBACNzP,EAAM+S,kBACN/S,EAAM0P,2BAENtd,EAAOI,KAAKoD,IAAI,oDAEhBxD,EAAOU,QAAQgN,aACXjJ,KAAM2Q,EACNvI,MAAO7M,EAAOK,MAAM+U,GAAgB7J,WACrC,GAEHvL,EAAOW,QAAQsS,OACfjT,EAAOW,QAAQgH,OAGf3H,EAAOW,QAAQuS,sBAlCnBtF,GAAMyP,iBAENrd,EAAOI,KAAKoD,IAAI,0BAEhBxD,EAAOU,QAAQuT,WAAWvB,GAGrB1S,EAAOyC,MAAMG,OAAO8P,EAAoB,GAAGiB,YAAYC,QAExD5T,EAAOW,QAAQuS,gBAgCvBlT,GAAOM,GAAG+C,cAIdwc,EAAUI,iBAAmB,SAAUrS,GAGnC5N,EAAOW,QAAQgX,QAGf3X,EAAOW,QAAQqB,QAAQ2V,QAEvB/J,EAAMyP,kBAOVwC,EAAUM,gBAAkB,WAExBngB,EAAOU,QAAQiN,qBAGf3N,EAAOW,QAAQgX,QACf3X,EAAOW,QAAQsS,QAOnB4M,EAAUK,kBAAoB,WAE1BlgB,EAAOW,QAAQgX,QAEV3X,EAAOW,QAAQqM,OAAOkN,gBAEvBla,EAAOW,QAAQqM,OAAO2K,QACtB3X,EAAOU,QAAQiR,cAMvBkO,EAAUtT,gBAAkB,SAAUqB,GAElCiS,EAAUsB,yCAEVnhB,EAAOU,QAAQiN,mBAAmBC,EAAM7I,QAExC/E,EAAOM,GAAG+C,YAEV,IACI+d,GADA9G,EAAeta,EAAOW,QAAQqM,OAAOuN,kBAmBzC,IAb4B,IAAxBD,EAAazT,QAEb7G,EAAOW,QAAQqM,OAAO2K,QAKU,QAAhC/J,EAAM7I,OAAOwS,iBAEbvX,EAAOc,MAAM0f,wBAIkB,OAA/BxgB,EAAOU,QAAQoQ,YAAsB,CAKrC,GAAIuQ,GAAmBrhB,EAAOyC,MAAMG,OAAOiE,OAAS,EAAI7G,EAAOyC,MAAMG,OAAOiE,OAAS,EAAI;AAezF,GAZI7G,EAAOyC,MAAMG,OAAOiE,SAOpBua,EAAkBphB,EAAOU,QAAQmR,mBAAmB7R,EAAOyC,MAAMG,OAAOye,KAKxErhB,EAAOyC,MAAMG,OAAOiE,QAAgE,KAAtD7G,EAAOyC,MAAMG,OAAOye,GAAkB1N,aAAsByN,EAAgB3R,QAAQvE,MAAQlL,EAAOsB,SAASG,mBAE1IzB,EAAOc,MAAM8e,WAAWyB,OAErB,CAGH,GAAIjM,GAAiBpV,EAAOsB,SAASG,kBAErCzB,GAAOU,QAAQgN,aACXjJ,KAAQ2Q,EACRvI,MAAQ7M,EAAOK,MAAM+U,GAAgB7J,WAIN,IAA/BvL,EAAOyC,MAAMG,OAAOiE,OAEpB7G,EAAOc,MAAM8e,WAAWyB,GAKxBrhB,EAAOc,MAAMsS,eAAeiO,GASpCrhB,EAAOW,QAAQsS,OACfjT,EAAOW,QAAQgH,WAOf3H,GAAOW,QAAQsS,OACfjT,EAAOW,QAAQgH,OAGf3H,EAAOW,QAAQW,SAASqW,QACxB3X,EAAOW,QAAQqB,QAAQ2V,OAK3B,IAAI2J,IAAgBthB,EAAOU,QAAQoQ,YAAY6C,YAAYC,OACvD2N,EAAkBvhB,EAAOU,QAAQoQ,YAAYrB,QAAQvE,KACrDsW,EAAgBD,GAAmBvhB,EAAOsB,SAASG,kBAIvDzB,GAAOW,QAAQkX,iBAEVyJ,GAGDthB,EAAOU,QAAQgR,YAId8P,GAAiBF,GAGlBthB,EAAOW,QAAQuS,kBAcvB2M,EAAUsB,uCAAyC,WAE/C,GAAIhQ,GAAaxM,OAAOyM,eACpBC,EAAaF,EAAUE,WACvBoQ,GAAO,CAEX,IAA6B,IAAzBtQ,EAAUsL,WAEVzc,EAAOU,QAAQqQ,wBAAyB,MAErC,CAeH,IAbK/Q,EAAOI,KAAKmG,UAAU8K,KAEvBA,EAAaA,EAAWpM,YAKM,QAA9BoM,EAAWkG,kBAEXkK,GAAO,GAI0B,QAA9BpQ,EAAWkG,kBAEdlG,EAAaA,EAAWpM,WAEU,QAA9BoM,EAAWkG,kBAEXkK,GAAO,GAIPpQ,GAAcjN,SAAS2N,QAS/B/R,EAAOU,QAAQqQ,wBAAyB0Q,IAUhD5B,EAAUlT,qBAAuB,SAAUiB,GAEvC,GAAIlB,GAAShG,IAEb1G,GAAOW,QAAQ0M,QAAUX,EAAO+C,QAAQhL,KAExCzE,EAAOW,QAAQqB,QAAQ6L,YAAYD,GACnC5N,EAAOW,QAAQgX,SAKnBkI,EAAUrT,kBAAoB,WAErBxM,EAAO0B,MAAMM,QAAQ0O,UAAUC,SAAS,UAMzC3Q,EAAOW,QAAQqB,QAAQ2V,QAJvB3X,EAAOW,QAAQqB,QAAQ2F,QAa/BkY,EAAU/S,aAAe,SAAUc,GAE/B,GAAIf,GAAQnG,IAEZ,QAAQkH,EAAMoP,SAEV,IAAKhd,GAAOI,KAAKoF,KAAKW,KACtB,IAAKnG,GAAOI,KAAKoF,KAAKY,MAClBpG,EAAOY,SAAS8gB,8BAChB,MAEJ,KAAK1hB,GAAOI,KAAKoF,KAAKC,UAClBzF,EAAOY,SAAS+gB,iBAAiB9U,EAAOe,EACxC,MAEJ,KAAK5N,GAAOI,KAAKoF,KAAKU,GACtB,IAAKlG,GAAOI,KAAKoF,KAAKS,KAClBjG,EAAOY,SAASghB,8BAU5B/B,EAAU6B,6BAA+B,WAErC,GAGIG,GAHA1Q,EAAcxM,OAAOyM,eACrBxO,EAAc5C,EAAOyC,MAAMG,OAC3Bkf,EAAc3Q,EAAUE,UAI5B,KAAKyQ,EAED,OAAO,CAKX,MAAsC,QAA/BA,EAAYvK,iBAEfsK,EAAoBC,EAAY7c,WAChC6c,EAAoBD,CAOxB,KAFA,GAAIE,GAAuB,EAEpBD,GAAelf,EAAOmf,IAEzBA,GAQJ,KAAKD,EAAYnO,YAGb,WADA3T,GAAOc,MAAMsS,eAAe2O,EAQhC,IAGIC,GACAC,EAJAC,GAAsB,EACtBnB,GAAsB,CAoB1B,OAfAiB,GAAYF,EAAY/R,WAAW+R,EAAY/R,WAAWlJ,OAAS,GAI/Dob,EAFAjiB,EAAOI,KAAKmG,UAAUyb,GAEJhiB,EAAOU,QAAQ8S,+BAA+BwO,EAAWA,EAAUjS,WAAWlJ,QAI9Emb,EAItBE,EAAmB/Q,EAAUE,YAAc4Q,EAC3ClB,EAAsBkB,EAAgBpb,QAAUsK,EAAUsD,aAEpDyN,GAAsBnB,MAO5B/gB,GAAOc,MAAMsS,eAAe2O,IALxB/hB,EAAOI,KAAKoD,IAAI,wDACT,IAWfqc,EAAU+B,0BAA4B,WAElC,GAGIC,GAHA1Q,EAAcxM,OAAOyM,eACrBxO,EAAc5C,EAAOyC,MAAMG,OAC3Bkf,EAAc3Q,EAAUE,UAI5B,KAAKyQ,EAED,OAAO,CAOX,IAAgC,IAA3B3Q,EAAUsD,aAEX,OAAO,CAKX,MAAsC,QAA/BqN,EAAYvK,iBAEfsK,EAAoBC,EAAY7c,WAChC6c,EAAoBD,CAOxB,KAFA,GAAIE,GAAuB,EAEpBD,GAAelf,EAAOmf,IAEzBA,GAOJ,IAGII,GACAF,EAJAG,GAAsB,EACtBC,GAAsB,CAS1B,OAAKP,GAAYnO,aAOjBwO,EAAaL,EAAY/R,WAAW,GAIhCkS,EAFAjiB,EAAOI,KAAKmG,UAAU4b,GAEJniB,EAAOU,QAAQ8S,+BAA+B2O,EAAY,GAI1DA,EAItBC,EAAsBjR,EAAUE,YAAc4Q,EAC9CI,EAAiD,IAA3BlR,EAAUsD,kBAE3B2N,GAAqBC,GAEtBriB,EAAOc,MAAMwhB,mBAAmBP,SAtBhC/hB,GAAOc,MAAMwhB,mBAAmBP,IAgCxClC,EAAUU,oBAAsB,WAE5B,GAAInL,GAAkBpV,EAAOsB,SAASG,kBAEtCzB,GAAOU,QAAQgN,aACXjJ,KAAQ2Q,EACRvI,MAAQ7M,EAAOK,MAAM+U,GAAgB7J,WACtC,GAEHvL,EAAOW,QAAQsS,OACfjT,EAAOW,QAAQgH,QAInBkY,EAAU8B,iBAAmB,SAAU9U,EAAOe,GAE1C,GACIuO,GACAoG,EACAvI,EAHAtH,EAAoB1S,EAAOc,MAAM6R,sBAKrC,IAAI6P,EAAc5U,EAAM7I,QAAS,CAG7B,GAAiC,IAA7B6I,EAAM7I,OAAOqY,MAAMxJ,OAMnB,MAJA/G,GAAM+E,SAUd,GAAI/E,EAAM8G,YAAYC,OAAQ,CAK1B,GAHAuI,EAAkBnc,EAAOU,QAAQqT,WACjCwO,EAAkBpG,EAAMsG,UAAYtG,EAAMiC,aAEtCpe,EAAOc,MAAMqO,SAASuT,WAAcH,IAAmBviB,EAAOyC,MAAMG,OAAO8P,EAAoB,GAM/F,MAJA1S,GAAOU,QAAQ2U,YAAY3C,GAU9B6P,GAED1V,EAAM+E,SAKVoI,EAAwBha,EAAO0B,MAAMc,SAASuN,WAAWlJ,OAK3B,IAA1BmT,GAGAha,EAAOU,QAAQoQ,YAAc,KAG7B9Q,EAAOM,GAAGgN,kBAGVtN,EAAOM,GAAG+C,aAGVsB,OAAOwO,WAAW,WAEdnT,EAAOc,MAAMwhB,mBAAmB,IAEjC,KAI6B,IAA5BtiB,EAAOc,MAAMoT,WAGblU,EAAOc,MAAMwhB,mBAAmBtiB,EAAOc,MAAMoT,YAK7ClU,EAAOc,MAAMsS,eAAepT,EAAOc,MAAMoT,YAMjDlU,EAAOW,QAAQsS,OAEVjT,EAAOW,QAAQ+W,QAEhB1X,EAAOW,QAAQgH,OAKnB3H,EAAOM,GAAG+C,aAGVuK,EAAMyP,kBAiBVwC,EAAU8C,oBAAsB,WAE5B,GAAIjQ,GAAoB1S,EAAOc,MAAM6R,uBAKjCiQ,EAAW,GAAIC,kBAAiB7iB,EAAOY,SAASkiB,wBAKhDhZ,GACAiZ,YAAY,EACZC,WAAW,EACXC,eAAe,EACfC,SAAU,EAIdN,GAASO,QAAQnjB,EAAOyC,MAAMG,OAAO8P,GAAoB5I,IAa7D+V,EAAU9S,mBAAqB,SAAUa,GAGrC,IAAK4U,EAAc5U,EAAM7I,QAAzB,CAOA6I,EAAMyP,gBAEN,IAAI+F,GAAiBpjB,EAAOU,QAAQ4W,kBAAkB1J,EAAM7I,QACxD+L,EAAc9Q,EAAOU,QAAQoQ,WAGjC,IAAKsS,EAAL,CAOA,GAMIC,GACAC,EAPAC,EAAY3V,EAAM4V,cAAcC,QAAQ,aACxCC,EAAY9V,EAAM4V,cAAcC,QAAQ,cAGxClN,EAAUvW,EAAOa,KAAKiR,KAAK,MAAO,OAClCmE,EAAU,GAAIjW,GAAOiB,UAAUd,KAAKH,EAAOiB,UAAUkV,OAAOC,MAKhEkN,GAAWlf,SAASuf,yBAEI,IAAnBJ,EAAS3P,QAEVyP,EAAYpN,EAAQI,MAAMkN,GAC1BhN,EAAI/G,UAAY6T,GAIhB9M,EAAIqN,UAAYF,EAAU7G,UAS9B,KALA,GAAI/K,GAAM+R,EAKD/R,EAAOyE,EAAI4L,YAEhB0B,EAAWP,EAAS1a,YAAYkJ,EAKpC,KAAI9R,EAAOK,MAAMyQ,EAAYrB,QAAQvE,MAAM4Y,qBAEnC9jB,EAAOqB,MAAM0iB,OAAOnW,GAF5B,CASA,GAAIuD,GAAWgL,CAEfhL,GAAYxM,OAAOyM,eAEnB+K,EAAQhL,EAAU6C,WAAW,GAC7BmI,EAAM6H,iBAEN7H,EAAM8H,WAAWX,GAGbO,IAEA1H,EAAQA,EAAMO,aACdP,EAAM+H,cAAcL,GACpB1H,EAAMG,UAAS,GACfnL,EAAU2N,kBACV3N,EAAU4N,SAAS5C,QAS3B0D,EAAUiD,uBAAyB,SAAUqB,GAEzC,GAAIC,GAAO1d,IASXyd,GAAU3I,QAAQ,SAAU/F,GAExBzV,EAAOU,QAAQW,MAAMzB,KAAKwkB,EAAM3O,MASxCoK,EAAUpT,0BAA4B,WAQlC,GAAI4X,GAAkBrkB,EAAOU,QAAQoQ,YAAYrB,QAAQvE,IAEzDlL,GAAOW,QAAQW,SAASsW,OAAOyM,GAG/BrkB,EAAOW,QAAQqB,QAAQ2V,QACvB3X,EAAOW,QAAQW,SAAS8W,oBAQ5B,IAAIoK,GAAgB,SAAUzd,GAE1B,GAAIuf,IAAoB,QAAS,WAEjC,OAAQA,GAAiBnN,QAAQpS,EAAOqS,WAAY,EAIxD,OAAOyI,SdkoGL,SAASpgB,EAAQD,GAEtB,Ye9lIDC,GAAOD,QAAW,SAAUqB,GAkTxB,MA7SAA,GAAKe,QAAU,WAEX,GAAIA,GAAUwC,SAASkE,cAAc,MAIrC,OAFA1G,GAAQmI,WAAa,eAEdnI,GAOXf,EAAK2B,SAAW,WAEZ,GAAIA,GAAW4B,SAASkE,cAAc,MAItC,OAFA9F,GAASuH,WAAa,cAEfvH,GAIX3B,EAAK0jB,QAAU,WAEX,GAAI1X,GAAQzI,SAASkE,cAAc,MAInC,OAFAuE,GAAM9C,WAAa,WAEZ8C,GAOXhM,EAAKF,QAAU,WAEX,GAAI6jB,GAAMpgB,SAASkE,cAAc,MAIjC,OAFAkc,GAAIza,WAAa,aAEVya,GAIX3jB,EAAK0J,eAAiB,WAElB,GAAI3I,GAAUwC,SAASkE,cAAc,MAIrC,OAFA1G,GAAQ8O,UAAUvE,IAAI,uBAEfvK,GAOXf,EAAKgB,cAAgB,WAEjB,GAAI2iB,GAAMpgB,SAASkE,cAAc,MAIjC,OAFAkc,GAAIza,WAAa,oBAEVya,GAOX3jB,EAAKmK,qBAAuB,WAExB,GAAIpJ,GAAUwC,SAASkE,cAAc,MAIrC,OAFA1G,GAAQmI,WAAa,6BAEdnI,GAOXf,EAAKoK,qBAAuB,WAExB,GAAIrJ,GAAUwC,SAASkE,cAAc,MAIrC,OAFA1G,GAAQmI,WAAa,6BAEdnI,GAIXf,EAAK8c,aAAe,WAEhB,GAAI7P,GAAQ1J,SAASkE,cAAc,QASnC,OAPAwF,GAAMrJ,KAAc,QACpBqJ,EAAM/D,WAAc,eACpB+D,EAAMoL,YAAc,sBACpBpL,EAAML,aAAa,OAAQ,eAE3BK,EAAML,aAAa,YAAa,aAEzBK,GAOXjN,EAAK2J,aAAe,WAEhB,GAAIqC,GAAQzI,SAASkE,cAAc,MAInC,OAFAuE,GAAM9C,WAAa,sBAEZ8C,GAOXhM,EAAKuB,cAAgB,WAEjB,GAAId,GAAW8C,SAASkE,cAAc,MAItC,OAFAhH,GAASyI,WAAa,cAEfzI,GAIXT,EAAKyB,gBAAkB,WAEnB,GAAIiU,GAAMnS,SAASkE,cAAc,MAIjC,OAFAiO,GAAI7F,UAAUvE,IAAI,uBAEXoK,GAIX1V,EAAK+J,gBAAkB,WAEnB,GAAI2L,GAAMnS,SAASkE,cAAc,MAIjC,OAFAiO,GAAI7F,UAAUvE,IAAI,sBAEXoK,GAIX1V,EAAKoB,WAAa,WAEd,GAAIyK,GAAStI,SAASkE,cAAc,OAKpC,OAHAoE,GAAO3C,UAAY,mBAGZ2C,GAOX7L,EAAK6J,eAAiB,WAElB,GAAI+Z,GAAUrgB,SAASkE,cAAc,OAOrC,OALAmc,GAAQ1a,UAAY,2BAGpB0a,EAAQjV,UAAY,8BAEbiV,GAQX5jB,EAAKmB,QAAU,WAEX,GAAIJ,GAAUwC,SAASkE,cAAc,MAIrC,OAFA1G,GAAQmI,UAAY,oBAEbnI,GAaXf,EAAK2K,cAAgB,SAAU/G,EAAMigB,GAEjC,GAAIhY,GAAatI,SAASkE,cAAc,MACpCqc,EAAYvgB,SAASkE,cAAc,KACnCsc,EAAYxgB,SAASkE,cAAc,OAYvC,OAVAoE,GAAO+C,QAAQhL,KAAOA,EACtBiI,EAAOe,aAAa,QAAShJ,GAE7BkgB,EAASjU,UAAUvE,IAAIuY,GACvBE,EAAUlU,UAAUvE,IAAI,2BAGxBO,EAAO9D,YAAY+b,GACnBjY,EAAO9D,YAAYgc,GAEZlY,GAYX7L,EAAKoL,oBAAsB,SAAUxH,EAAMigB,GAEvC,GAAIhY,GAAatI,SAASkE,cAAc,UACpCqc,EAAYvgB,SAASkE,cAAc,IAQvC,OANAoE,GAAOjI,KAAO,SACdiI,EAAO+C,QAAQhL,KAAOA,EACtBkgB,EAASjU,UAAUvE,IAAIuY,GAEvBhY,EAAO9D,YAAY+b,GAEZjY,GAOX7L,EAAKgM,MAAQ,SAAUuK,EAAS1W,GAE5B,GAAIoR,GAAO1N,SAASkE,cAAc8O,EAIlC,OAFAtF,GAAKtC,UAAY9O,GAAW,GAErBoR,GAUXjR,EAAKiR,KAAO,SAAWsF,EAASrN,EAAW8a,GAEvC,GAAIre,GAAKpC,SAASkE,cAAe8O,EAIjC,IAFKrN,IAAYvD,EAAGuD,UAAYA,GAE3B8a,EAED,IAAK,GAAI7Y,KAAQ6Y,GAEbre,EAAGwF,GAAQ6Y,EAAW7Y,EAM9B,OAAOxF,IAOX3F,EAAK0O,iBAAmB,WAEpB,GAAI3N,GAAUwC,SAASkE,cAAc,MAIrC,OAFA1G,GAAQ8O,UAAUvE,IAAI,yBAEfvK,GAIJf,QfolIL,SAASpB,EAAQD,GAEtB,YgBx4IDC,GAAOD,QAAW,SAAUsB,GAExB,GAAId,GAASb,MAAMa,MAqQnB,OAhQAc,GAAMoT,WAAa,KAKnBpT,EAAM4a,OAAS,KAKf5a,EAAMgkB,iBAAmB,KAQzBhkB,EAAMkS,IAAM,SAAWxM,EAAIqI,EAAO6M,GAE9BA,EAASA,GAAU5a,EAAM4a,QAAU,EACnC7M,EAASA,GAAU/N,EAAMgkB,kBAAoB,CAE7C,IACIC,GADAC,EAASxe,EAAGuJ,UAchB,IATIgV,EAFmB,IAAlBC,EAAOne,OAEIL,EAIAwe,EAAOnW,GAKG,QAAtBrI,EAAG+Q,gBAGH,WADA/Q,GAAGoX,OAKH5d,GAAOI,KAAKmG,UAAUwe,KAEtBA,EAAY/kB,EAAOU,QAAQ8S,+BAA+BuR,EAAWA,EAAUhV,WAAWlJ,QAI9F,IAAIsV,GAAY/X,SAASiY,cACrBlL,EAAYxM,OAAOyM,cAEvBzM,QAAOwO,WAAW,WAEdgJ,EAAMqC,SAASuG,EAAWrJ,GAC1BS,EAAM+B,OAAO6G,EAAWrJ,GAExBvK,EAAU2N,kBACV3N,EAAU4N,SAAS5C,GAEnBnc,EAAOc,MAAM0f,yBAEd,KAQP1f,EAAM0f,sBAAwB,WAG1B,GAGIqB,GAHA1Q,EAAcxM,OAAOyM,eACrBxO,EAAc5C,EAAOyC,MAAMG,OAC3Bkf,EAAc3Q,EAAUE,UAG5B,IAAKyQ,EAAL,CAOA,KAAsC,QAA/BA,EAAYvK,iBAEfsK,EAAoBC,EAAY7c,WAChC6c,EAAoBD,CAOxB,KAFA,GAAIE,GAAuB,EAEpBD,GAAelf,EAAOmf,IAEzBA,GAIJjhB,GAAMoT,WAAa6N,IAOvBjhB,EAAM6R,qBAAuB,WAEzB,MAAO7R,GAAMoT,YAOjBpT,EAAMsS,eAAiB,SAAUvE,GAE7B,GAAIjM,GAAS5C,EAAOyC,MAAMG,OACtBqiB,EAAYriB,EAAOiM,EAAQ,EAE/B,KAAKoW,EAGD,WADAjlB,GAAOI,KAAKoD,IAAI,yBASpB,KAAKyhB,EAAUlV,WAAWlJ,OAAQ,CAE9B,GAAIqe,GAAmB9gB,SAAS2O,eAAe,GAE/CkS,GAAUrc,YAAYsc,GAI1BllB,EAAOc,MAAMoT,WAAarF,EAAQ,EAClC7O,EAAOc,MAAMkS,IAAIiS,EAAW,EAAG,GAC/BjlB,EAAOU,QAAQiN,mBAAmBsX,IAQtCnkB,EAAM8e,WAAa,SAAU/Q,GAEzB,GAAIjM,GAAS5C,EAAOyC,MAAMG,OACtB2S,EAAc3S,EAAOiM,EAEzB,IAAM0G,EAAN,CAUA,IAAKA,EAAYxF,WAAWlJ,OAAQ,CAEhC,GAAIqe,GAAmB9gB,SAAS2O,eAAe,GAE/CwC,GAAY3M,YAAYsc,GAI5BllB,EAAOc,MAAMoT,WAAarF,EAC1B7O,EAAOc,MAAMkS,IAAIuC,EAAa,EAAG,GACjCvV,EAAOU,QAAQiN,mBAAmB4H,KAOtCzU,EAAMwhB,mBAAqB,SAAUzT,GAEjCA,EAAQA,GAAS,CAEjB,IAEIsW,GACAC,EACAF,EAJAtiB,EAAS5C,EAAOyC,MAAMG,OACtByiB,EAAgBziB,EAAOiM,EAAQ,EAMnC,OAAKwW,IAOLF,EAAgBnlB,EAAOU,QAAQ8S,+BAA+B6R,EAAeA,EAActV,WAAWlJ,QACtGue,EAAwBD,EAActe,OAMjCwe,EAActV,WAAWlJ,SAE1Bqe,EAAmB9gB,SAAS2O,eAAe,IAC3CsS,EAAczc,YAAYsc,IAG9BllB,EAAOc,MAAMoT,WAAarF,EAAQ,EAClC7O,EAAOc,MAAMkS,IAAIqS,EAAeA,EAActV,WAAWlJ,OAAS,EAAGue,OACrEplB,GAAOU,QAAQiN,mBAAmB/K,EAAOiM,EAAQ,SApB7C7O,GAAOI,KAAKoD,IAAI,8BAwBxB1C,EAAMqO,UAEFuT,QAAU,WAEN,GAAIvR,GAAkBxM,OAAOyM,eACzBqD,EAAkBtD,EAAUsD,aAC5BpD,EAAkBF,EAAUE,WAC5B+P,EAAkBphB,EAAOU,QAAQmR,mBAAmBR,GACpDiU,EAAkBlE,EAAgBrR,WAAW,EAE5C/P,GAAOI,KAAKmG,UAAU8K,KAEvBA,EAAaA,EAAWpM,WAI5B,IAAIsgB,GAAelU,IAAeiU,EAAcvV,WAAW,GACvDyV,EAAgC,IAAjB/Q,CAEnB,OAAO8Q,IAAeC,GAI1BxE,SAAW,WAEP,GAAI7P,GAAexM,OAAOyM,eACtBqD,EAAetD,EAAUsD,aACzBpD,EAAeF,EAAUE,UAG7B,QAAQA,IAAeA,EAAWxK,QAAU4N,IAAiBpD,EAAWxK,SAKzE/F,QhB83IL,SAASrB,EAAQD,GAEtB,YiBvoJDC,GAAOD,QAAW,SAAUuB,GAExB,GAAIf,GAASb,MAAMa,OAEfiQ,KAEAwV,EAAa,SAAUnkB,GAEvB2O,EAAM9G,KAAK7H,EAIX,KAFA,GAAIuN,GAAQ,EAEJA,EAAQoB,EAAMpJ,QAAUoJ,EAAMpJ,OAAS,GAElB,WAArBoJ,EAAMpB,GAAOpK,MAA0C,UAArBwL,EAAMpB,GAAOpK,MAOnDwL,EAAMpB,GAAO8I,QACb1H,EAAMyV,OAAO7W,EAAO,IANhBA,IAuMZ,OA3LA9N,GAAc0J,aAAe,WAEzB,GAAIkb,GAAS3lB,EAAOa,KAAKiR,KAAK,MAAO,0BAIrC,OAFA9R,GAAO0B,MAAMX,cAAgBqD,SAAS2N,KAAKnJ,YAAY+c,GAEhDA,GASX5kB,EAAc6kB,YAAc,SAAUC,EAAUjY,GAE5C5N,EAAOe,cAAc+kB,cAAcC,QAAS,yCAA0CthB,KAAMmJ,EAAMnJ,QAoBtG1D,EAAc+kB,aAAe,SAAUE,GA8CnC,QAASC,GAAO3kB,GAEZ,IAAMA,IAAYA,EAASykB,QAGvB,WADA/lB,GAAOI,KAAKoD,IAAI,+CAKpBlC,GAASmD,KAAOnD,EAASmD,MAAQ,QACjCnD,EAAS4kB,KAAqB,IAAd5kB,EAAS4kB,MAAa,GAEtC,IAAItkB,GAAU5B,EAAOa,KAAKiR,KAAK,MAAO,oBAClCiU,EAAU/lB,EAAOa,KAAKiR,KAAK,MAAO,6BAClChE,EAAQ9N,EAAOa,KAAKiR,KAAK,QAAS,2BAClCqU,EAAQnmB,EAAOa,KAAKiR,KAAK,OAAQ,4BACjCsU,EAAYpmB,EAAOa,KAAKiR,KAAK,OAAQ,+BAEzCiU,GAAQpS,YAAcrS,EAASykB,QAC/BI,EAAMxS,YAAcrS,EAAS+kB,OAAS,KACtCD,EAAUzS,YAAcrS,EAASglB,WAAa,SAE9CtmB,EAAOmB,UAAUgL,IAAIga,EAAO,QAASI,GACrCvmB,EAAOmB,UAAUgL,IAAIia,EAAW,QAASI,GAEzC5kB,EAAQgH,YAAYmd,GAEC,UAAjBzkB,EAASmD,MAET7C,EAAQgH,YAAYkF,GAIxBlM,EAAQgH,YAAYud,GAEC,UAAjB7kB,EAASmD,MAAqC,WAAjBnD,EAASmD,MAEtC7C,EAAQgH,YAAYwd,GAIxBxkB,EAAQ8O,UAAUvE,IAAI,oBAAsB7K,EAASmD,MACrD7C,EAAQ6N,QAAQhL,KAAOnD,EAASmD,KAEhCqhB,EAAelkB,EACf6C,EAAenD,EAASmD,KACxBgiB,EAAenlB,EAASmlB,QACxBC,EAAeplB,EAASolB,OACxBC,EAAe7Y,EAEM,UAAjBxM,EAASmD,MAAqC,WAAjBnD,EAASmD,MAEtCE,OAAOwO,WAAWwE,EAAOrW,EAAS4kB,MAM1C,QAASje,KAELjI,EAAO0B,MAAMX,cAAc6H,YAAYkd,GACvCa,EAAW/I,QAEX5d,EAAO0B,MAAMX,cAAc2P,UAAUvE,IAAI,4CAEzCxH,OAAOwO,WAAW,WAEdnT,EAAO0B,MAAMX,cAAc2P,UAAUkB,OAAO,6CAE7C,KAEH6T,GAAYhhB,KAAMA,EAAMkT,MAAOA,IAInC,QAASA,KAELmO,EAAalU,SAxHjB,GAAIkU,GAAe,KACfY,EAAe,KACfjiB,EAAe,KACfgiB,EAAe,KACfE,EAAe,KAEfJ,EAAiB,WAIjB,GAFA5O,IAEuB,kBAAZ8O,GAMX,MAAY,UAARhiB,MAEAgiB,GAAQE,EAAWvJ,WAKvBqJ,MAIAD,EAAgB,WAEhB7O,IAEsB,kBAAX+O,IAMXA,IA+FJ,OAPIV,KAEAC,EAAOD,GACP/d,MAKAge,OAAQA,EACRhe,KAAMA,EACN0P,MAAOA,IAKf5W,EAAc6lB,MAAQ,WAElB5mB,EAAO0B,MAAMX,cAAcyO,UAAY,GACvCS,MAIGlP,QjB6nJL,SAAStB,EAAQD,GAEtB,YkBt1JDC,GAAOD,QAAW,SAAUwB,GAExB,GAAIhB,GAASb,MAAMa,MAwBnB,OArBAgB,GAAO6lB,oBAAsB,SAAUrU,EAAW2M,GAE9Cnf,EAAOU,QAAQgN,aACXjJ,KAAQ+N,EAAU/N,KAClBoI,MAAQ2F,EAAUjH,QACdkI,KAAO0L,EAAI3P,eASvBxO,EAAOwQ,kBAAoB,SAAUM,GAEjC,MAAOA,GAAKrL,UAAYzG,EAAOI,KAAKgF,UAAUC,KAC1CyM,EAAKpB,UAAUC,SAAS3Q,EAAOM,GAAGyJ,UAAUC,kBAI7ChJ,QlBi2JL,SAASvB,EAAQD,EAASH,GAE/B,YmBh4JDI,GAAOD,QAAW,SAAUyB,GAExB,GAAI6lB,GAAUznB,EAAQ,IAKlB8W,GAEAC,OAEI2Q,MACIhnB,KACAinB,GACIC,MAAM,EACNliB,OAAQ,SACRmiB,IAAK,YAETlS,KACAmS,KACAC,UACAC,MACAC,UASZ,OAJArmB,GAAUkV,OAASA,EAEnBlV,EAAUd,KAAO2mB,EAEV7lB,QnB24JL,SAASxB,EAAQD,EAASH,GoB96JhC,GAAAkoB,GAAAC,GAAA,SAAAC,EAAAC,GAEAH,EAAA,EAAAC,EAAA,kBAAAD,KAAA3nB,KAAAJ,EAAAH,EAAAG,EAAAC,GAAA8nB,IAAAjjB,SAAAkjB,IAAA/nB,EAAAD,QAAAgoB,KAMC9gB,KAAA,WAMD,QAAAihB,GAAA7d,GAEA,GAAA8d,GAAA9d,EAAA,KACAid,EAAAngB,OAAApB,KAAAoiB,GAEAC,EAAAd,EACA3Z,IAAA,SAAA0a,GAAwB,aAAAF,GAAAE,KACxBC,MAAA,SAAAtjB,GAA6B,iBAAAA,GAAA,YAAAA,GAAA,aAAAA,GAE7B,KAAAojB,EACA,SAAAtjB,OAAA,gCAGAmC,MAAAoD,SAKA,QAAAke,GAAAlW,GACA,MAAAmW,GAAA9Q,QAAArF,EAAAoW,aAAA,EAIA,QAAAC,GAAArW,GACA,MAAAsW,GAAAjR,QAAArF,EAAAoW,aAAA,EAsGA,QAAAG,GAAAvW,GACA,MAAA1N,UAAAikB,iBAAAvW,EACAwW,WAAAC,UAAAD,WAAAE,aAAAF,WAAAG,aACA,SAGA,QAAAC,GAAA5e,EAAAoe,EAAApW,GACA,wBAAAhI,GAAAid,KAAAmB,GACApe,EAAAid,KAAAmB,GAAApW,GAEAhI,EAAAid,KAAAmB,GAIA,QAAAS,GAAA7W,EAAA8W,GACA,yBAAAA,IAEK,iBAAAA,KACLA,EAMA,QAAAC,GAAAC,EAAAF,EAAA9W,GACA,GAAAiX,GAAAD,EAAA9c,KAAAgd,aAEA,OAAAJ,MAAA,IAEK,kBAAAA,GAAAG,IACLH,EAAAG,GAAAD,EAAA1L,MAAAtL,GACK,mBAAA8W,GAAAG,KAEAH,EAAAG,MAAA,GAEA,gBAAAH,GAAAG,IACLH,EAAAG,KAAAD,EAAA1L,QAjJA,GAAA6K,IAAA,8DAKAG,GAAA,mDAkJA,OA7IAT,GAAA7jB,UAAAuS,MAAA,SAAAvG,GACA,GAAAmZ,GAAA7kB,SAAAkE,cAAA,MAKA,OAJA2gB,GAAAzZ,UAAAM,EAEApJ,KAAAwiB,UAAAD,GAEAA,EAAAzZ,WAGAmY,EAAA7jB,UAAAolB,UAAA,SAAAjkB,GACA,GAAAkkB,GAAAd,EAAApjB,GACA6M,EAAAqX,EAAAhH,YACA,IAAArQ,EAEA,EAEA,KAAAA,EAAAsX,WAIA,GAAAtX,EAAArL,WAAA4iB,KAAAC,UAAA,CAkBA,GAAAxX,EAAArL,WAAA4iB,KAAAE,aAAA,CACAtkB,EAAA4O,YAAA/B,GACApL,KAAAwiB,UAAAjkB,EACA,OAGA,GACAukB,GADAC,EAAAtB,EAAArW,EAEA2X,KACAD,EAAArc,MAAArJ,UAAA4lB,KAAA9pB,KAAAkS,EAAA/B,WAAAiY,GAKA,IAAA2B,KAAA1kB,aACA2kB,EACA5B,EAAA/iB,IACA+iB,EAAAlW,IACA6X,EAEAzB,EAAApW,EAAAoW,SAAAc,cAEAJ,EAAAF,EAAAhiB,KAAAoD,OAAAoe,EAAApW,GAEA+X,EAAAJ,GAAAD,CAIA,IAAAK,GAAAlB,EAAA7W,EAAA8W,KACAliB,KAAAoD,OAAAggB,yBAAAF,EAAA,CAEA,cAAA9X,EAAAoW,UAAA,UAAApW,EAAAoW,SACA,KAAApW,EAAA/B,WAAAlJ,OAAA,GACA5B,EAAAC,aAAA4M,EAAA/B,WAAA,GAAA+B,EAGA7M,GAAA4O,YAAA/B,GAEApL,KAAAwiB,UAAAjkB,EACA,OAIA,OAAA+hB,GAAA,EAAqBA,EAAAlV,EAAAiR,WAAAlc,OAA4BmgB,GAAA,GACjD,GAAA8B,GAAAhX,EAAAiR,WAAAiE,EAEA6B,GAAAC,EAAAF,EAAA9W,KACAA,EAAAiY,gBAAAjB,EAAA9c,MAEAgb,GAAA,GAKAtgB,KAAAwiB,UAAApX,GAGAA,EAAAsX,YAAA,MArEA,SAAAtX,EAAA5N,KAAA0P,SACA9B,EAAAkY,wBAAAhC,EAAAlW,EAAAkY,yBACAlY,EAAAmY,oBAAAjC,EAAAlW,EAAAmY,qBAAA,CACAhlB,EAAA4O,YAAA/B,GACApL,KAAAwiB,UAAAjkB,EACA,aAiEK6M,EAAAqX,EAAAhkB,gBA6CLwiB,KpBu7JM,SAASloB,EAAQD,GAEtB,YqBxmKDC,GAAOD,QAAU,SAAU0B,GAEvB,GAAIlB,GAASb,MAAMa,MAgFnB,OA9EAkB,GAAQ4M,MAAc,KACtB5M,EAAQ4P,YAAc,KAEtB5P,EAAQuX,eAAiB,SAAU/D,GAE/BxT,EAAQ4P,YAAc4D,EACtBxT,EAAQ4M,MAAMsP,MAAQlc,EAAQ4P,YAAYrB,QAAQJ,QAAU,IAIhEnO,EAAQmY,cAAgB,SAAUxU,GAE9B,GAAIqlB,GAAYrlB,EAAEE,OAAOqY,MAAQlc,EAAQipB,cAActlB,EAAEE,OAAOqY,MAEhElc,GAAQ4P,YAAYrB,QAAQJ,OAAS6a,EAEZ,KAArBA,EAAUtW,OAEV1S,EAAQ4P,YAAYJ,UAAUvE,IAAInM,EAAOM,GAAGyJ,UAAUM,mBAItDnJ,EAAQ4P,YAAYJ,UAAUkB,OAAO5R,EAAOM,GAAGyJ,UAAUM,oBAMjEnJ,EAAQiY,qBAAuB,SAAUtU,GAEjCA,EAAEmY,SAAWhd,EAAOI,KAAKoF,KAAKG,QAE9Bd,EAAEwY,iBACFxY,EAAE8b,kBAEF9b,EAAEE,OAAOqlB,OACTpqB,EAAOW,QAAQW,SAASqW,UAMhCzW,EAAQkY,mBAAqB,SAAUvU,GAE/BA,EAAEmY,SAAWhd,EAAOI,KAAKoF,KAAKS,MAAQpB,EAAEmY,SAAWhd,EAAOI,KAAKoF,KAAKW,MAEpEtB,EAAE8b,mBAMVzf,EAAQipB,cAAgB,SAAUE,GAa9B,IAAK,GAXDC,IACI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAClD,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAClD,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAEtDC,GACI,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,KAAM,IAAK,IAAK,IACnD,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAAK,IAClD,IAAK,IAAK,KAAM,KAAM,MAAO,GAAI,IAAK,GAAI,IAAK,KAAM,MAGpDvV,EAAI,EAAGA,EAAIsV,EAAGzjB,OAAQmO,IAE3BqV,EAASA,EAAOG,MAAMF,EAAGtV,IAAIyV,KAAKF,EAAGvV,IACrCqV,EAASA,EAAOG,MAAMF,EAAGtV,GAAGgU,eAAeyB,KAAKF,EAAGvV,GAAGgU,cAM1D,OAFAqB,GAASA,EAAOK,QAAQ,kBAAmB,MAMxCxpB,QrBomKL,SAASzB,EAAQD,GAEtB,YsBrrKDC,GAAOD,QAAU,SAAU2B,GAEvB,GAAIwpB,KAiLJ,OAxKAxpB,GAAUypB,OAAS,WAEf,GAAIC,GAAY,SAAU7lB,EAAS8lB,GAE/B,GAAIC,KAEJD,GAAUA,GAAWH,CAErB,KAAK,GAAI3V,GAAI,EAAGA,EAAI8V,EAAQjkB,OAAQmO,IAAK,CAErC,GAAIgW,GAAWF,EAAQ9V,EAEnBgW,GAAShmB,UAAYA,GAErB+lB,EAAmB5hB,KAAK6hB,GAMhC,MAAOD,IAIPE,EAAS,SAAUC,EAAWJ,GAE9B,GAAIK,KAEJL,GAAUA,GAAWH,CAErB,KAAK,GAAI3V,GAAI,EAAGA,EAAI8V,EAAQjkB,OAAQmO,IAAK,CAErC,GAAIgW,GAAWF,EAAQ9V,EAEnBgW,GAASvmB,OAASymB,GAElBC,EAAkBhiB,KAAK6hB,GAM/B,MAAOG,IAIPC,EAAY,SAAUC,EAASP,GAE/B,GAAIQ,KAEJR,GAAUA,GAAWH,CAErB,KAAK,GAAI3V,GAAI,EAAGA,EAAI8V,EAAQjkB,OAAQmO,IAAK,CAErC,GAAIgW,GAAWF,EAAQ9V,EAEnBgW,GAASK,UAAYA,GAErBC,EAAqBniB,KAAK6hB,GAMlC,MAAOM,IAIPC,EAAM,SAAUvmB,EAASkmB,EAAWG,GAEpC,GAAIxa,GAAS8Z,CAWb,OATI3lB,KACA6L,EAASga,EAAU7lB,EAAS6L,IAE5Bqa,IACAra,EAASoa,EAAOC,EAAWra,IAE3Bwa,IACAxa,EAASua,EAAUC,EAASxa,IAEzBA,EAAO,IAId2a,EAAM,SAAUxmB,EAASkmB,EAAWG,GAEpC,GAAIxa,GAAS8Z,CAWb,OATI3lB,KACA6L,EAASga,EAAU7lB,EAAS6L,IAE5Bqa,IACAra,EAASoa,EAAOC,EAAWra,IAE3Bwa,IACAxa,EAASua,EAAUC,EAASxa,IAEzBA,EAIX,QACIga,UAAcA,EACdI,OAAcA,EACdG,UAAcA,EACdG,IAAcA,EACdC,IAAcA,MAKtBrqB,EAAUgL,IAAM,SAAUnH,EAASkmB,EAAWG,EAASI,GAEnDzmB,EAAQ0mB,iBAAiBR,EAAWG,EAASI,EAE7C,IAAIvnB,IACAc,QAASA,EACTP,KAAMymB,EACNG,QAASA,GAGTM,EAAuBxqB,EAAUypB,OAAOW,IAAIvmB,EAASkmB,EAAWG,EAE/DM,IAEDhB,EAAaxhB,KAAKjF,IAM1B/C,EAAUyQ,OAAS,SAAU5M,EAASkmB,EAAWG,GAE7CrmB,EAAQ4mB,oBAAoBV,EAAWG,EAIvC,KAAK,GAFDQ,GAAoB1qB,EAAUypB,OAAOY,IAAIxmB,EAASkmB,EAAWG,GAExDrW,EAAI,EAAGA,EAAI6W,EAAkBhlB,OAAQmO,IAAK,CAE/C,GAAInG,GAAQ8b,EAAaxT,QAAQ0U,EAAkB7W,GAE/CnG,GAAQ,GAER8b,EAAajF,OAAO7W,EAAO,KAQvC1N,EAAU2qB,UAAY,WAElBnB,EAAavd,IAAI,SAAUC,GAEvBlM,EAAUyQ,OAAOvE,EAAQrI,QAASqI,EAAQ5I,KAAM4I,EAAQge,YAMhElqB,EAAU4qB,IAAM,SAAU/mB,EAASkmB,EAAWG,GAE1C,MAAOlqB,GAAUypB,OAAOY,IAAIxmB,EAASkmB,EAAWG,IAI7ClqB,QtB4qKL,SAAS1B,EAAQD,GAEtB,YAEA,IAAIiE,GAA4B,kBAAXC,SAAoD,gBAApBA,QAAOC,SAAwB,SAAUC,GAAO,aAAcA,IAAS,SAAUA,GAAO,MAAOA,IAAyB,kBAAXF,SAAyBE,EAAIC,cAAgBH,QAAUE,IAAQF,OAAOI,UAAY,eAAkBF,GuBt2KvQnE,GAAOD,QAAU,SAAU4B,GAEvB,GAAIpB,GAASb,MAAMa,MAsFnB,OApFAoB,GAAU4qB,YAAc,WAEpBhsB,EAAO0B,MAAME,QAAQgQ,SACrB5R,EAAO0B,MAAMX,cAAc6Q,UAI/BxQ,EAAU6qB,eAAiB,WAEvB,IAAK,GAAI/gB,KAAQlL,GAAOK,MAEsB,kBAA/BL,GAAOK,MAAM6K,GAAMghB,SAE1BlsB,EAAOK,MAAM6K,GAAMghB,WAQ/B9qB,EAAU+qB,eAAiB,WAIvB,IAAK,GAFDC,GAAUhoB,SAASioB,qBAAqB,UAEnCrX,EAAI,EAAGA,EAAIoX,EAAQvlB,OAAQmO,IAE5BoX,EAAQpX,GAAGtV,GAAGyX,QAAQnX,EAAOE,cAAgB,IAE7CksB,EAAQpX,GAAGpD,SACXoD,MAmBZ5T,EAAU8qB,QAAU,SAAU5qB,GAErBA,GAAgC,YAApB,mBAAOA,GAAP,YAAAmC,EAAOnC,MAMpBA,EAAShB,KAETc,EAAU4qB,cACVhsB,EAAOmB,UAAU2qB,aAIjBxqB,EAAS8qB,SAEThrB,EAAU+qB,iBAIV7qB,EAAS+H,SAETjI,EAAU6qB,iBAIV3qB,EAAShB,IAAMgB,EAAS8qB,SAAW9qB,EAASlB,YAErCjB,OAAMa,SAMdoB,QvBs2KL,SAAS3B,EAAQD,GAEtB,YwBh8KDC,GAAOD,QAAU,SAAU6B,GAEvB,GAAIrB,GAASb,MAAMa,OAEfssB,IAEJjrB,GAAM0B,QAAU,WAEZ,GAAI1C,GAAQL,EAAOK,KAEnB,KAAK,GAAI6K,KAAQ7K,GAERA,EAAM6K,GAAMqhB,uBAA0Bpf,MAAMqf,QAAQnsB,EAAM6K,GAAMqhB,wBAMrElsB,EAAM6K,GAAMqhB,sBAAsBnf,IAAI,SAAUqf,GAG5CH,EAASnjB,KAAKsjB,IAMtB,OAAO1oB,SAAQC,WAQnB3C,EAAM0iB,OAAS,SAAUnW,GAErB,GAAI8e,GAAgB9e,EAAM4V,eAAiB7e,OAAO6e,cAC9C9iB,EAAUgsB,EAAcjJ,QAAQ,QAEhC5S,EAAS8b,EAAQjsB,EASrB,OAPImQ,KAEAjD,EAAMyP,iBACNzP,EAAM0P,4BAIHzM,EAQX,IAAI8b,GAAU,SAAUtC,GAEpB,GAAIxZ,IAAU,EACVnQ,EAAUV,EAAOU,QAAQoQ,YACzB5H,EAAUxI,EAAQ+O,QAAQvE,IAuB9B,OArBAohB,GAASlf,IAAK,SAAUqf,GAEpB,GAAIG,GAAYH,EAAQI,MAAMC,KAAKzC,GAC/B0C,EAAYH,GAAaA,EAAU,EAElCG,IAASA,IAAU1C,EAAOzW,SAGtBlT,EAAQiT,YAAYC,QAAU1K,GAAUlJ,EAAOsB,SAASG,oBAEzDurB,IAIJP,EAAQ7rB,SAASypB,EAAQoC,GACzB5b,GAAS,KAMVA,GAIPmc,EAAmB,WAGnBhtB,EAAOU,QAAQgN,aAEXjJ,KAAOzE,EAAOsB,SAASG,mBACvBoL,MAAQ7M,EAAOK,MAAML,EAAOsB,SAASG,oBAAoB8J,QACrDkI,KAAO,OAGZ,GAIP,OAAOpS","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.5.4\");\n\t editor.scriptPrefix = 'cdx-script-';\n\t\n\t var init = function init() {\n\t\n\t editor.core = __webpack_require__(1);\n\t editor.tools = __webpack_require__(2);\n\t editor.ui = __webpack_require__(3);\n\t editor.transport = __webpack_require__(4);\n\t editor.renderer = __webpack_require__(5);\n\t editor.saver = __webpack_require__(6);\n\t editor.content = __webpack_require__(7);\n\t editor.toolbar = __webpack_require__(8);\n\t editor.callback = __webpack_require__(12);\n\t editor.draw = __webpack_require__(13);\n\t editor.caret = __webpack_require__(14);\n\t editor.notifications = __webpack_require__(15);\n\t editor.parser = __webpack_require__(16);\n\t editor.sanitizer = __webpack_require__(17);\n\t editor.anchors = __webpack_require__(19);\n\t editor.listeners = __webpack_require__(20);\n\t editor.destroyer = __webpack_require__(21);\n\t editor.paste = __webpack_require__(22);\n\t };\n\t\n\t /**\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.tools.prepare).then(editor.paste.prepare).then(editor.transport.prepare).then(editor.renderer.makeBlocksFromData).then(editor.ui.saveInputs).catch(function (error) {\n\t\n\t editor.core.log('Initialization failed with error: %o', 'warn', error);\n\t });\n\t };\n\t\n\t return editor;\n\t}({});\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\t\n\t/**\n\t * Codex Editor Core\n\t *\n\t * @author Codex Team\n\t * @version 1.1.2\n\t */\n\t\n\tmodule.exports = function (core) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * @public\n\t *\n\t * Editor preparing method\n\t * @return Promise\n\t */\n\t core.prepare = function (userSettings) {\n\t\n\t return new Promise(function (resolve, reject) {\n\t\n\t if (userSettings) {\n\t\n\t editor.settings.tools = userSettings.tools || editor.settings.tools;\n\t }\n\t\n\t if (userSettings.data) {\n\t\n\t editor.state.blocks = userSettings.data;\n\t }\n\t\n\t if (userSettings.initialBlockPlugin) {\n\t\n\t editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\n\t }\n\t\n\t if (userSettings.uploadImagesUrl) {\n\t\n\t editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;\n\t }\n\t\n\t editor.hideToolbar = userSettings.hideToolbar;\n\t\n\t editor.nodes.textarea = document.getElementById(userSettings.textareaId || editor.settings.textareaId);\n\t\n\t if (_typeof(editor.nodes.textarea) === undefined || editor.nodes.textarea === null) {\n\t\n\t reject(Error(\"Textarea wasn't found by ID: #\" + userSettings.textareaId));\n\t } else {\n\t\n\t resolve();\n\t }\n\t });\n\t };\n\t\n\t /**\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 * Checks passed object for emptiness\n\t * @require ES5 - Object.keys\n\t * @param {object}\n\t */\n\t core.isEmpty = function (obj) {\n\t\n\t return Object.keys(obj).length === 0;\n\t };\n\t\n\t /**\n\t * Native Ajax\n\t */\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 script = void 0;\n\t\n\t /** Script is already loaded */\n\t if (!instanceName) {\n\t\n\t reject('Instance name is missed');\n\t } else if (document.getElementById(editor.scriptPrefix + instanceName)) {\n\t\n\t resolve(scriptPath);\n\t }\n\t\n\t script = document.createElement('SCRIPT');\n\t script.async = true;\n\t script.defer = true;\n\t script.id = editor.scriptPrefix + instanceName;\n\t\n\t script.onload = function () {\n\t\n\t resolve(scriptPath);\n\t };\n\t\n\t script.onerror = function () {\n\t\n\t reject(scriptPath);\n\t };\n\t\n\t script.src = scriptPath;\n\t document.head.appendChild(script);\n\t });\n\t };\n\t\n\t return core;\n\t}({});\n\n/***/ },\n/* 2 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t* Module working with plugins\n\t*/\n\tmodule.exports = function () {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Initialize plugins before using\n\t * Ex. Load scripts or call some internal methods\n\t * @return Promise\n\t */\n\t function prepare() {\n\t\n\t return new Promise(function (resolve_, reject_) {\n\t\n\t Promise.resolve()\n\t\n\t /**\n\t * Compose a sequence of plugins that requires preparation\n\t */\n\t .then(function () {\n\t\n\t var pluginsRequiresPreparation = [],\n\t allPlugins = editor.tools;\n\t\n\t for (var pluginName in allPlugins) {\n\t\n\t var plugin = allPlugins[pluginName];\n\t\n\t if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {\n\t\n\t continue;\n\t }\n\t\n\t pluginsRequiresPreparation.push(plugin);\n\t }\n\t\n\t /**\n\t * If no one passed plugins requires preparation, finish prepare() and go ahead\n\t */\n\t if (!pluginsRequiresPreparation.length) {\n\t\n\t resolve_();\n\t }\n\t\n\t return pluginsRequiresPreparation;\n\t })\n\t\n\t /** Wait plugins while they prepares */\n\t .then(waitAllPluginsPreparation_).then(function () {\n\t\n\t editor.core.log('Plugins loaded', 'info');\n\t resolve_();\n\t }).catch(function (error) {\n\t\n\t reject_(error);\n\t });\n\t });\n\t }\n\t\n\t /**\n\t * @param {array} plugins - list of tools that requires preparation\n\t * @return {Promise} resolved while all plugins will be ready or failed\n\t */\n\t function waitAllPluginsPreparation_(plugins) {\n\t\n\t /**\n\t * @calls allPluginsProcessed__ when all plugins prepared or failed\n\t */\n\t return new Promise(function (allPluginsProcessed__) {\n\t\n\t /**\n\t * pluck each element from queue\n\t * First, send resolved Promise as previous value\n\t * Each plugins \"prepare\" method returns a Promise, that's why\n\t * reduce current element will not be able to continue while can't get\n\t * a resolved Promise\n\t *\n\t * If last plugin is \"prepared\" then go to the next stage of initialization\n\t */\n\t plugins.reduce(function (previousValue, plugin, iteration) {\n\t\n\t return previousValue.then(function () {\n\t\n\t /**\n\t * Wait till plugins prepared\n\t * @calls pluginIsReady__ when plugin is ready or failed\n\t */\n\t return new Promise(function (pluginIsReady__) {\n\t\n\t callPluginsPrepareMethod_(plugin).then(pluginIsReady__).then(function () {\n\t\n\t plugin.available = true;\n\t }).catch(function (error) {\n\t\n\t editor.core.log('Plugin \\xAB' + plugin.type + '\\xBB was not loaded. Preparation failed because %o', 'warn', error);\n\t plugin.available = false;\n\t plugin.loadingMessage = error;\n\t\n\t /** Go ahead even some plugin has problems */\n\t pluginIsReady__();\n\t }).then(function () {\n\t\n\t /** If last plugin has problems then just ignore and continue */\n\t if (iteration == plugins.length - 1) {\n\t\n\t allPluginsProcessed__();\n\t }\n\t });\n\t });\n\t });\n\t }, Promise.resolve());\n\t });\n\t }\n\t\n\t var callPluginsPrepareMethod_ = function callPluginsPrepareMethod_(plugin) {\n\t\n\t return plugin.prepare(plugin.config || {});\n\t };\n\t\n\t return {\n\t prepare: prepare\n\t };\n\t}();\n\n/***/ },\n/* 3 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor UI module\n\t *\n\t * @author Codex Team\n\t * @version 1.1.3\n\t */\n\t\n\tmodule.exports = function (ui) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Basic editor classnames\n\t */\n\t ui.className = {\n\t\n\t /**\n\t * @const {string} BLOCK_CLASSNAME - redactor blocks name\n\t */\n\t BLOCK_CLASSNAME: 'ce-block',\n\t\n\t /**\n\t * @const {String} wrapper for plugins content\n\t */\n\t BLOCK_CONTENT: 'ce-block__content',\n\t\n\t /**\n\t * @const {String} BLOCK_STRETCHED - makes block stretched\n\t */\n\t BLOCK_STRETCHED: 'ce-block--stretched',\n\t\n\t /**\n\t * @const {String} BLOCK_HIGHLIGHTED - adds background\n\t */\n\t BLOCK_HIGHLIGHTED: 'ce-block--focused',\n\t\n\t /**\n\t * @const {String} - highlights covered blocks\n\t */\n\t BLOCK_IN_FEED_MODE: 'ce-block--feed-mode',\n\t\n\t /**\n\t * @const {String} - Block with anchor\n\t */\n\t BLOCK_WITH_ANCHOR: 'ce-block--anchor',\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, blockButtons, blockSettings, showSettingsButton, showTrashButton, toolbox, plusButton;\n\t\n\t /** Make editor wrapper */\n\t wrapper = editor.draw.wrapper();\n\t\n\t /** Append editor wrapper after initial textarea */\n\t editor.core.insertAfter(editor.nodes.textarea, wrapper);\n\t\n\t /** Append block with notifications to the document */\n\t editor.notifications.createHolder();\n\t\n\t /** Make toolbar and content-editable redactor */\n\t toolbar = editor.draw.toolbar();\n\t toolbarContent = editor.draw.toolbarContent();\n\t plusButton = editor.draw.plusButton();\n\t showSettingsButton = editor.draw.settingsButton();\n\t showTrashButton = editor.toolbar.settings.makeRemoveBlockButton();\n\t blockSettings = editor.draw.blockSettings();\n\t blockButtons = editor.draw.blockButtons();\n\t toolbox = editor.draw.toolbox();\n\t redactor = editor.draw.redactor();\n\t\n\t /** settings */\n\t var defaultSettings = editor.draw.defaultSettings(),\n\t pluginSettings = editor.draw.pluginsSettings();\n\t\n\t /** Add default and plugins settings */\n\t blockSettings.appendChild(pluginSettings);\n\t blockSettings.appendChild(defaultSettings);\n\t\n\t /** Make blocks buttons\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 && tool.displayInToolbox) {\n\t\n\t editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\n\t continue;\n\t }\n\t\n\t if (typeof tool.render != 'function') {\n\t\n\t editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\n\t continue;\n\t }\n\t\n\t if (!tool.displayInToolbox) {\n\t\n\t continue;\n\t } else {\n\t\n\t /** if tools is for toolbox */\n\t toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\n\t\n\t editor.nodes.toolbox.appendChild(toolButton);\n\t\n\t editor.nodes.toolbarButtons[toolName] = toolButton;\n\t }\n\t }\n\t\n\t /**\n\t * 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 editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n\t\n\t /** All keydowns on Redactor zone */\n\t editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n\t\n\t /** All keydowns on Document */\n\t editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false);\n\t\n\t /**\n\t * Mouse click to radactor\n\t */\n\t editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false);\n\t\n\t /**\n\t * Clicks to the Plus button\n\t */\n\t editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n\t\n\t /**\n\t * Clicks to SETTINGS button in toolbar\n\t */\n\t editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false);\n\t\n\t /**\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.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n\t }\n\t };\n\t\n\t ui.addBlockHandlers = function (block) {\n\t\n\t if (!block) return;\n\t\n\t /**\n\t * Block keydowns\n\t */\n\t editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n\t\n\t /**\n\t * Pasting content from another source\n\t * We have two type of sanitization\n\t * First - uses deep-first search algorithm to get sub nodes,\n\t * sanitizes whole Block_content and replaces cleared nodes\n\t * This method is deprecated\n\t * Method is used in editor.callback.blockPaste(event)\n\t *\n\t * Secont - uses Mutation observer.\n\t * Observer \"observe\" DOM changes and send changings to callback.\n\t * Callback gets changed node, not whole Block_content.\n\t * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n\t *\n\t * Method is used in editor.callback.blockPasteViaSanitize(event)\n\t *\n\t * @uses html-janitor\n\t * @example editor.callback.blockPasteViaSanitize(event), the second method.\n\t *\n\t */\n\t editor.listeners.add(block, 'paste', editor.callback.blockPasteCallback, false);\n\t\n\t editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\n\t };\n\t\n\t /** getting all contenteditable elements */\n\t ui.saveInputs = function () {\n\t\n\t var redactor = editor.nodes.redactor;\n\t\n\t editor.state.inputs = [];\n\t\n\t /** Save all inputs in global variable state */\n\t var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\n\t\n\t Array.prototype.map.call(inputs, function (current) {\n\t\n\t if (!current.type || current.type == 'text' || current.type == 'textarea') {\n\t\n\t editor.state.inputs.push(current);\n\t }\n\t });\n\t };\n\t\n\t /**\n\t * Adds first initial block on empty redactor\n\t */\n\t ui.addInitialBlock = function () {\n\t\n\t var initialBlockType = editor.settings.initialBlockPlugin,\n\t initialBlock;\n\t\n\t if (!editor.tools[initialBlockType]) {\n\t\n\t editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\n\t return;\n\t }\n\t\n\t initialBlock = editor.tools[initialBlockType].render();\n\t\n\t initialBlock.setAttribute('data-placeholder', 'Расскажите свою историю...');\n\t\n\t editor.content.insertBlock({\n\t type: initialBlockType,\n\t block: initialBlock\n\t });\n\t\n\t editor.content.workingNodeChanged(initialBlock);\n\t };\n\t\n\t ui.setInlineToolbarButtonBehaviour = function (button, type) {\n\t\n\t editor.listeners.add(button, 'mousedown', function (event) {\n\t\n\t editor.toolbar.inline.toolClicked(event, type);\n\t }, false);\n\t };\n\t\n\t return ui;\n\t}({});\n\n/***/ },\n/* 4 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t *\n\t * Codex.Editor Transport Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (transport) {\n\t\n\t var editor = codex.editor;\n\t\n\t transport.input = null;\n\t\n\t /**\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 editor.listeners.add(input, 'change', editor.transport.fileSelected);\n\t\n\t editor.transport.input = input;\n\t };\n\t\n\t /** Clear input when files is uploaded */\n\t transport.clearInput = function () {\n\t\n\t /** Remove old input */\n\t this.input = null;\n\t\n\t /** Prepare new one */\n\t this.prepare();\n\t };\n\t\n\t /**\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/* 5 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Renderer Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (renderer) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Asyncronously parses input JSON to redactor blocks\n\t */\n\t renderer.makeBlocksFromData = function () {\n\t\n\t /**\n\t * If redactor is empty, add first paragraph to start writing\n\t */\n\t if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {\n\t\n\t editor.ui.addInitialBlock();\n\t return;\n\t }\n\t\n\t Promise.resolve()\n\t\n\t /** First, get JSON from state */\n\t .then(function () {\n\t\n\t return editor.state.blocks;\n\t })\n\t\n\t /** Then, start to iterate they */\n\t .then(editor.renderer.appendBlocks)\n\t\n\t /** Write log if something goes wrong */\n\t .catch(function (error) {\n\t\n\t editor.core.log('Error while parsing JSON: %o', 'error', error);\n\t });\n\t };\n\t\n\t /**\n\t * Parses JSON to blocks\n\t * @param {object} data\n\t * @return Primise -> nodeList\n\t */\n\t renderer.appendBlocks = function (data) {\n\t\n\t var blocks = data.items;\n\t\n\t /**\n\t * Sequence of one-by-one blocks appending\n\t * Uses to save blocks order after async-handler\n\t */\n\t var nodeSequence = Promise.resolve();\n\t\n\t for (var index = 0; index < blocks.length; index++) {\n\t\n\t /** Add node to sequence at specified index */\n\t editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\n\t }\n\t };\n\t\n\t /**\n\t * Append node at specified index\n\t */\n\t renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\n\t\n\t /** We need to append node to sequence */\n\t nodeSequence\n\t\n\t /** first, get node async-aware */\n\t .then(function () {\n\t\n\t return editor.renderer.getNodeAsync(blocks, index);\n\t })\n\t\n\t /**\n\t * second, compose editor-block from JSON object\n\t */\n\t .then(editor.renderer.createBlockFromData)\n\t\n\t /**\n\t * now insert block to redactor\n\t */\n\t .then(function (blockData) {\n\t\n\t /**\n\t * blockData has 'block', 'type' and 'stretched' information\n\t */\n\t editor.content.insertBlock(blockData);\n\t\n\t /** Pass created block to next step */\n\t return blockData.block;\n\t })\n\t\n\t /** Log if something wrong with node */\n\t .catch(function (error) {\n\t\n\t editor.core.log('Node skipped while parsing because %o', 'error', error);\n\t });\n\t };\n\t\n\t /**\n\t * Asynchronously returns block data from blocksList by index\n\t * @return Promise to node\n\t */\n\t renderer.getNodeAsync = function (blocksList, index) {\n\t\n\t return Promise.resolve().then(function () {\n\t\n\t return {\n\t tool: blocksList[index],\n\t position: index\n\t };\n\t });\n\t };\n\t\n\t /**\n\t * Creates editor block by JSON-data\n\t *\n\t * @uses render method of each plugin\n\t *\n\t * @param {Object} toolData.tool\n\t * { header : {\n\t * text: '',\n\t * type: 'H3', ...\n\t * }\n\t * }\n\t * @param {Number} toolData.position - index in input-blocks array\n\t * @return {Object} with type and Element\n\t */\n\t renderer.createBlockFromData = function (toolData) {\n\t\n\t /** New parser */\n\t var block,\n\t tool = toolData.tool,\n\t pluginName = tool.type,\n\t anchor = tool.anchor,\n\t cover = tool.cover;\n\t\n\t /** Get first key of object that stores plugin name */\n\t // for (var pluginName in blockData) break;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].render != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have \\xABrender\\xBB method');\n\t }\n\t\n\t if (editor.tools[pluginName].available === false) {\n\t\n\t block = editor.draw.unavailableBlock();\n\t\n\t block.innerHTML = editor.tools[pluginName].loadingMessage;\n\t\n\t /**\n\t * Saver will extract data from initial block data by position in array\n\t */\n\t block.dataset.inputPosition = toolData.position;\n\t } else {\n\t\n\t /** New Parser */\n\t block = editor.tools[pluginName].render(tool.data);\n\t }\n\t\n\t /** is first-level block stretched */\n\t var stretched = editor.tools[pluginName].isStretched || false;\n\t\n\t /** Retrun type and block */\n\t return {\n\t type: pluginName,\n\t block: block,\n\t stretched: stretched,\n\t cover: cover,\n\t anchor: anchor\n\t };\n\t };\n\t\n\t return renderer;\n\t}({});\n\n/***/ },\n/* 6 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Saver\n\t *\n\t * @author Codex Team\n\t * @version 1.0.2\n\t */\n\t\n\tmodule.exports = function (saver) {\n\t\n\t var editor = codex.editor;\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 anchor = block.dataset.anchor;\n\t\n\t /** Check for plugin existance */\n\t if (!editor.tools[pluginName]) {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB not found');\n\t }\n\t\n\t /** Check for plugin having render method */\n\t if (typeof editor.tools[pluginName].save != 'function') {\n\t\n\t throw Error('Plugin \\xAB' + pluginName + '\\xBB must have save method');\n\t }\n\t\n\t /** Result saver */\n\t var blockContent = block.childNodes[0],\n\t pluginsContent = blockContent.childNodes[0],\n\t savedData,\n\t position,\n\t output,\n\t coverFlag = false;\n\t\n\t /** If plugin wasn't available then return data from cache */\n\t if (editor.tools[pluginName].available === false) {\n\t\n\t position = pluginsContent.dataset.inputPosition;\n\t\n\t savedData = codex.editor.state.blocks.items[position].data;\n\t coverFlag = codex.editor.state.blocks.items[position].cover;\n\t anchor = codex.editor.state.blocks.items[position].anchor;\n\t } else {\n\t\n\t savedData = editor.tools[pluginName].save(pluginsContent);\n\t coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t\n\t if (editor.tools[pluginName].validate) {\n\t\n\t var result = editor.tools[pluginName].validate(savedData);\n\t\n\t /**\n\t * Do not allow invalid data\n\t */\n\t if (!result) return;\n\t }\n\t }\n\t\n\t output = {\n\t type: pluginName,\n\t anchor: anchor,\n\t data: savedData\n\t };\n\t\n\t /** Marks Blocks that will be in main page */\n\t output.cover = coverFlag;\n\t\n\t editor.state.jsonOutput.push(output);\n\t };\n\t\n\t return saver;\n\t}({});\n\n/***/ },\n/* 7 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Content Module\n\t * Works with DOM\n\t *\n\t * @author Codex Team\n\t * @version 1.3.12\n\t */\n\t\n\tmodule.exports = function (content) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * Links to current active block\n\t * @type {null | Element}\n\t */\n\t content.currentNode = null;\n\t\n\t /**\n\t * clicked in redactor area\n\t * @type {null | Boolean}\n\t */\n\t content.editorAreaHightlighted = null;\n\t\n\t /**\n\t * 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 if (targetBlock.classList.contains(editor.ui.className.BLOCK_WITH_ANCHOR)) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t\n\t /**\n\t * Saving anchor\n\t */\n\t newBlock.dataset.anchor = targetBlock.dataset.anchor;\n\t\n\t /** Replacing */\n\t editor.nodes.redactor.replaceChild(newBlock, targetBlock);\n\t\n\t /**\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 anchor = blockData.anchor,\n\t isStretched = blockData.stretched;\n\t\n\t var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);\n\t\n\t if (cover === true) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\t }\n\t\n\t if (anchor) {\n\t\n\t newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t\n\t if (workingBlock) {\n\t\n\t editor.core.insertAfter(workingBlock, newBlock);\n\t } else {\n\t\n\t /**\n\t * If redactor is empty, append as first child\n\t */\n\t editor.nodes.redactor.appendChild(newBlock);\n\t }\n\t\n\t /**\n\t * Block handler\n\t */\n\t editor.ui.addBlockHandlers(newBlock);\n\t\n\t /**\n\t * Set new node as current\n\t */\n\t editor.content.workingNodeChanged(newBlock);\n\t\n\t /**\n\t * Save changes\n\t */\n\t editor.ui.saveInputs();\n\t\n\t if (needPlaceCaret) {\n\t\n\t /**\n\t * If we don't know input index then we set default value -1\n\t */\n\t var currentInputIndex = editor.caret.getCurrentInputIndex() || -1;\n\t\n\t if (currentInputIndex == -1) {\n\t\n\t var editableElement = newBlock.querySelector('[contenteditable]'),\n\t emptyText = document.createTextNode('');\n\t\n\t editableElement.appendChild(emptyText);\n\t editor.caret.set(editableElement, 0, 0);\n\t\n\t editor.toolbar.move();\n\t editor.toolbar.showPlusButton();\n\t } else {\n\t\n\t if (currentInputIndex === editor.state.inputs.length - 1) return;\n\t\n\t /** Timeout for browsers execution */\n\t window.setTimeout(function () {\n\t\n\t /** Setting to the new input */\n\t editor.caret.setToNextBlock(currentInputIndex);\n\t editor.toolbar.move();\n\t editor.toolbar.open();\n\t }, 10);\n\t }\n\t }\n\t\n\t /**\n\t * Block is inserted, wait for new click that defined focusing on editors area\n\t * @type {boolean}\n\t */\n\t content.editorAreaHightlighted = false;\n\t };\n\t\n\t /**\n\t * Replaces blocks with saving content\n\t * @protected\n\t * @param {Element} noteToReplace\n\t * @param {Element} newNode\n\t * @param {Element} blockType\n\t */\n\t content.switchBlock = function (blockToReplace, newBlock, tool) {\n\t\n\t tool = tool || editor.content.currentNode.dataset.tool;\n\t var newBlockComposed = 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, anchor) {\n\t\n\t var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),\n\t blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});\n\t\n\t blockContent.appendChild(block);\n\t newBlock.appendChild(blockContent);\n\t\n\t if (isStretched) {\n\t\n\t blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED);\n\t }\n\t\n\t newBlock.dataset.tool = tool;\n\t newBlock.dataset.anchor = anchor || '';\n\t return newBlock;\n\t };\n\t\n\t /**\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 /**\n\t * Finds closest Contenteditable parent from Element\n\t * @param {Element} node element looking from\n\t * @return {Element} node contenteditable\n\t */\n\t content.getEditableParent = function (node) {\n\t\n\t while (node && node.contentEditable != 'true') {\n\t\n\t node = node.parentNode;\n\t }\n\t\n\t return node;\n\t };\n\t\n\t return content;\n\t}({});\n\n/***/ },\n/* 8 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor toolbar module\n\t *\n\t * Contains:\n\t * - Inline toolbox\n\t * - Toolbox within plus button\n\t * - Settings section\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (toolbar) {\n\t\n\t var editor = codex.editor;\n\t\n\t toolbar.settings = __webpack_require__(9);\n\t toolbar.inline = __webpack_require__(10);\n\t toolbar.toolbox = __webpack_require__(11);\n\t\n\t /**\n\t * Margin between focused node and toolbar\n\t */\n\t toolbar.defaultToolbarHeight = 49;\n\t\n\t toolbar.defaultOffset = 34;\n\t\n\t toolbar.opened = false;\n\t\n\t toolbar.current = null;\n\t\n\t /**\n\t * @protected\n\t */\n\t toolbar.open = function () {\n\t\n\t if (editor.hideToolbar) {\n\t\n\t return;\n\t }\n\t\n\t editor.nodes.toolbar.classList.add('opened');\n\t this.opened = true;\n\t };\n\t\n\t /**\n\t * @protected\n\t */\n\t toolbar.close = function () {\n\t\n\t editor.nodes.toolbar.classList.remove('opened');\n\t\n\t toolbar.opened = false;\n\t toolbar.current = null;\n\t\n\t for (var button in editor.nodes.toolbarButtons) {\n\t\n\t editor.nodes.toolbarButtons[button].classList.remove('selected');\n\t }\n\t\n\t /** Close toolbox when toolbar is not displayed */\n\t editor.toolbar.toolbox.close();\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t toolbar.toggle = function () {\n\t\n\t if (!this.opened) {\n\t\n\t this.open();\n\t } else {\n\t\n\t this.close();\n\t }\n\t };\n\t\n\t toolbar.hidePlusButton = function () {\n\t\n\t editor.nodes.plusButton.classList.add('hide');\n\t };\n\t\n\t toolbar.showPlusButton = function () {\n\t\n\t editor.nodes.plusButton.classList.remove('hide');\n\t };\n\t\n\t /**\n\t * Moving toolbar to the specified node\n\t */\n\t toolbar.move = function () {\n\t\n\t /** Close Toolbox when we move toolbar */\n\t editor.toolbar.toolbox.close();\n\t\n\t if (!editor.content.currentNode) {\n\t\n\t return;\n\t }\n\t\n\t var newYCoordinate = editor.content.currentNode.offsetTop - editor.toolbar.defaultToolbarHeight / 2 + editor.toolbar.defaultOffset;\n\t\n\t editor.nodes.toolbar.style.transform = 'translate3D(0, ' + Math.floor(newYCoordinate) + 'px, 0)';\n\t\n\t /** Close trash actions */\n\t editor.toolbar.settings.hideRemoveActions();\n\t };\n\t\n\t return toolbar;\n\t}({});\n\n/***/ },\n/* 9 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Toolbar settings\n\t *\n\t * @version 1.0.4\n\t */\n\t\n\tmodule.exports = function (settings) {\n\t\n\t var editor = codex.editor;\n\t\n\t settings.opened = false;\n\t\n\t settings.setting = null;\n\t settings.actions = null;\n\t\n\t settings.cover = null;\n\t\n\t /**\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 editor.anchors.settingsOpened(editor.content.currentNode);\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, anchorInput;\n\t\n\t /** Clear block and append initialized settings */\n\t editor.nodes.defaultSettings.innerHTML = '';\n\t\n\t /** Init all default setting buttons */\n\t feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();\n\t anchorInput = editor.toolbar.settings.makeAnchorInput();\n\t\n\t /**\n\t * Fill defaultSettings\n\t */\n\t\n\t /**\n\t * Input for anchor for block\n\t */\n\t editor.nodes.defaultSettings.appendChild(anchorInput);\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: 'Вывести в ленте'\n\t };\n\t } else {\n\t\n\t data = {\n\t innerHTML: 'Не выводить в ленте'\n\t };\n\t }\n\t\n\t setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\n\t editor.listeners.add(setting, 'click', editor.toolbar.settings.updateFeedMode, false);\n\t\n\t return setting;\n\t };\n\t\n\t /**\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 settings.makeAnchorInput = function () {\n\t\n\t var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),\n\t hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),\n\t anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });\n\t\n\t editor.listeners.add(anchor, 'keydown', editor.anchors.keyDownOnAnchorInput);\n\t editor.listeners.add(anchor, 'keyup', editor.anchors.keyUpOnAnchorInput);\n\t editor.listeners.add(anchor, 'input', editor.anchors.anchorChanged);\n\t editor.listeners.add(anchor, 'blur', editor.anchors.anchorChanged);\n\t\n\t anchorWrapper.appendChild(hash);\n\t anchorWrapper.appendChild(anchor);\n\t\n\t editor.anchors.input = anchor;\n\t\n\t return anchorWrapper;\n\t };\n\t\n\t /**\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: '' }),\n\t actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\n\t confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent: 'Удалить блок' }),\n\t cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent: 'Отмена' });\n\t\n\t editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\n\t\n\t editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\n\t\n\t editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\n\t\n\t actionWrapper.appendChild(confirmAction);\n\t actionWrapper.appendChild(cancelAction);\n\t\n\t removeBlockWrapper.appendChild(settingButton);\n\t removeBlockWrapper.appendChild(actionWrapper);\n\t\n\t /** Save setting */\n\t editor.toolbar.settings.setting = settingButton;\n\t editor.toolbar.settings.actions = actionWrapper;\n\t\n\t return removeBlockWrapper;\n\t };\n\t\n\t settings.removeButtonClicked = function () {\n\t\n\t var action = editor.toolbar.settings.actions;\n\t\n\t if (action.classList.contains('opened')) {\n\t\n\t editor.toolbar.settings.hideRemoveActions();\n\t } else {\n\t\n\t editor.toolbar.settings.showRemoveActions();\n\t }\n\t\n\t editor.toolbar.toolbox.close();\n\t editor.toolbar.settings.close();\n\t };\n\t\n\t settings.cancelRemovingRequest = function () {\n\t\n\t editor.toolbar.settings.actions.classList.remove('opened');\n\t };\n\t\n\t settings.confirmRemovingRequest = function () {\n\t\n\t var currentBlock = editor.content.currentNode,\n\t firstLevelBlocksCount;\n\t\n\t currentBlock.remove();\n\t\n\t firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\t\n\t /**\n\t * If all blocks are removed\n\t */\n\t if (firstLevelBlocksCount === 0) {\n\t\n\t /** update currentNode variable */\n\t editor.content.currentNode = null;\n\t\n\t /** Inserting new empty initial block */\n\t editor.ui.addInitialBlock();\n\t }\n\t\n\t editor.ui.saveInputs();\n\t\n\t editor.toolbar.close();\n\t };\n\t\n\t settings.showRemoveActions = function () {\n\t\n\t editor.toolbar.settings.actions.classList.add('opened');\n\t };\n\t\n\t settings.hideRemoveActions = function () {\n\t\n\t editor.toolbar.settings.actions.classList.remove('opened');\n\t };\n\t\n\t return settings;\n\t}({});\n\n/***/ },\n/* 10 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Inline toolbar\n\t *\n\t * Contains from tools:\n\t * Bold, Italic, Underline and Anchor\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (inline) {\n\t\n\t var editor = codex.editor;\n\t\n\t inline.buttonsOpened = null;\n\t inline.actionsOpened = null;\n\t inline.wrappersOffset = null;\n\t\n\t /**\n\t * saving selection that need for execCommand for styling\n\t *\n\t */\n\t inline.storedSelection = null;\n\t\n\t /**\n\t * @protected\n\t *\n\t * Open inline toobar\n\t */\n\t inline.show = function () {\n\t\n\t var currentNode = editor.content.currentNode,\n\t tool = currentNode.dataset.tool,\n\t plugin;\n\t\n\t /**\n\t * tool allowed to open inline toolbar\n\t */\n\t plugin = editor.tools[tool];\n\t\n\t if (!plugin.showInlineToolbar) return;\n\t\n\t var selectedText = inline.getSelectionText(),\n\t toolbar = editor.nodes.inlineToolbar.wrapper;\n\t\n\t if (selectedText.length > 0) {\n\t\n\t /** Move toolbar and open */\n\t editor.toolbar.inline.move();\n\t\n\t /** Open inline toolbar */\n\t toolbar.classList.add('opened');\n\t\n\t /** show buttons of inline toolbar */\n\t editor.toolbar.inline.showButtons();\n\t }\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Closes inline toolbar\n\t */\n\t inline.close = function () {\n\t\n\t var toolbar = editor.nodes.inlineToolbar.wrapper;\n\t\n\t toolbar.classList.remove('opened');\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Moving toolbar\n\t */\n\t inline.move = function () {\n\t\n\t if (!this.wrappersOffset) {\n\t\n\t this.wrappersOffset = this.getWrappersOffset();\n\t }\n\t\n\t var coords = this.getSelectionCoords(),\n\t defaultOffset = 0,\n\t toolbar = editor.nodes.inlineToolbar.wrapper,\n\t newCoordinateX,\n\t newCoordinateY;\n\t\n\t if (toolbar.offsetHeight === 0) {\n\t\n\t defaultOffset = 40;\n\t }\n\t\n\t newCoordinateX = coords.x - this.wrappersOffset.left;\n\t newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;\n\t\n\t toolbar.style.transform = 'translate3D(' + Math.floor(newCoordinateX) + 'px, ' + Math.floor(newCoordinateY) + 'px, 0)';\n\t\n\t /** Close everything */\n\t editor.toolbar.inline.closeButtons();\n\t editor.toolbar.inline.closeAction();\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Tool Clicked\n\t */\n\t\n\t inline.toolClicked = function (event, type) {\n\t\n\t /**\n\t * For simple tools we use default browser function\n\t * For more complicated tools, we should write our own behavior\n\t */\n\t switch (type) {\n\t case 'createLink':\n\t editor.toolbar.inline.createLinkAction(event, type);break;\n\t default:\n\t editor.toolbar.inline.defaultToolAction(type);break;\n\t }\n\t\n\t /**\n\t * highlight buttons\n\t * after making some action\n\t */\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Saving wrappers offset in DOM\n\t */\n\t inline.getWrappersOffset = function () {\n\t\n\t var wrapper = editor.nodes.wrapper,\n\t offset = this.getOffset(wrapper);\n\t\n\t this.wrappersOffset = offset;\n\t return offset;\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Calculates offset of DOM element\n\t *\n\t * @param el\n\t * @returns {{top: number, left: number}}\n\t */\n\t inline.getOffset = function (el) {\n\t\n\t var _x = 0;\n\t var _y = 0;\n\t\n\t while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {\n\t\n\t _x += el.offsetLeft + el.clientLeft;\n\t _y += el.offsetTop + el.clientTop;\n\t el = el.offsetParent;\n\t }\n\t return { top: _y, left: _x };\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Calculates position of selected text\n\t * @returns {{x: number, y: number}}\n\t */\n\t inline.getSelectionCoords = function () {\n\t\n\t var sel = document.selection,\n\t range;\n\t var x = 0,\n\t y = 0;\n\t\n\t if (sel) {\n\t\n\t if (sel.type != 'Control') {\n\t\n\t range = sel.createRange();\n\t range.collapse(true);\n\t x = range.boundingLeft;\n\t y = range.boundingTop;\n\t }\n\t } else if (window.getSelection) {\n\t\n\t sel = window.getSelection();\n\t\n\t if (sel.rangeCount) {\n\t\n\t range = sel.getRangeAt(0).cloneRange();\n\t if (range.getClientRects) {\n\t\n\t range.collapse(true);\n\t var rect = range.getClientRects()[0];\n\t\n\t if (!rect) {\n\t\n\t return;\n\t }\n\t\n\t x = rect.left;\n\t y = rect.top;\n\t }\n\t }\n\t }\n\t return { x: x, y: y };\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Returns selected text as String\n\t * @returns {string}\n\t */\n\t inline.getSelectionText = function () {\n\t\n\t var selectedText = '';\n\t\n\t // all modern browsers and IE9+\n\t if (window.getSelection) {\n\t\n\t selectedText = window.getSelection().toString();\n\t }\n\t\n\t return selectedText;\n\t };\n\t\n\t /** Opens buttons block */\n\t inline.showButtons = function () {\n\t\n\t var buttons = editor.nodes.inlineToolbar.buttons;\n\t\n\t buttons.classList.add('opened');\n\t\n\t editor.toolbar.inline.buttonsOpened = true;\n\t\n\t /** highlight buttons */\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\t };\n\t\n\t /** Makes buttons disappear */\n\t inline.closeButtons = function () {\n\t\n\t var buttons = editor.nodes.inlineToolbar.buttons;\n\t\n\t buttons.classList.remove('opened');\n\t\n\t editor.toolbar.inline.buttonsOpened = false;\n\t };\n\t\n\t /** Open buttons defined action if exist */\n\t inline.showActions = function () {\n\t\n\t var action = editor.nodes.inlineToolbar.actions;\n\t\n\t action.classList.add('opened');\n\t\n\t editor.toolbar.inline.actionsOpened = true;\n\t };\n\t\n\t /** Close actions block */\n\t inline.closeAction = function () {\n\t\n\t var action = editor.nodes.inlineToolbar.actions;\n\t\n\t action.innerHTML = '';\n\t action.classList.remove('opened');\n\t editor.toolbar.inline.actionsOpened = false;\n\t };\n\t\n\t /**\n\t * Callback for keydowns in inline toolbar \"Insert link...\" input\n\t */\n\t var inlineToolbarAnchorInputKeydown_ = function inlineToolbarAnchorInputKeydown_(event) {\n\t\n\t if (event.keyCode != editor.core.keys.ENTER) {\n\t\n\t return;\n\t }\n\t\n\t var editable = editor.content.currentNode,\n\t storedSelection = editor.toolbar.inline.storedSelection;\n\t\n\t editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\t editor.toolbar.inline.setAnchor(this.value);\n\t\n\t /**\n\t * Preventing events that will be able to happen\n\t */\n\t event.preventDefault();\n\t event.stopImmediatePropagation();\n\t\n\t editor.toolbar.inline.clearRange();\n\t };\n\t\n\t /** Action for link creation or for setting anchor */\n\t inline.createLinkAction = function (event) {\n\t\n\t var isActive = this.isLinkActive();\n\t\n\t var editable = editor.content.currentNode,\n\t storedSelection = editor.toolbar.inline.saveSelection(editable);\n\t\n\t /** Save globally selection */\n\t editor.toolbar.inline.storedSelection = storedSelection;\n\t\n\t if (isActive) {\n\t\n\t /**\n\t * Changing stored selection. if we want to remove anchor from word\n\t * we should remove anchor from whole word, not only selected part.\n\t * The solution is than we get the length of current link\n\t * Change start position to - end of selection minus length of anchor\n\t */\n\t editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\t\n\t editor.toolbar.inline.defaultToolAction('unlink');\n\t } else {\n\t\n\t /** Create input and close buttons */\n\t var action = editor.draw.inputForLink();\n\t\n\t editor.nodes.inlineToolbar.actions.appendChild(action);\n\t\n\t editor.toolbar.inline.closeButtons();\n\t editor.toolbar.inline.showActions();\n\t\n\t /**\n\t * focus to input\n\t * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\n\t * Prevents event after showing input and when we need to focus an input which is in unexisted form\n\t */\n\t action.focus();\n\t event.preventDefault();\n\t\n\t /** Callback to link action */\n\t editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);\n\t }\n\t };\n\t\n\t inline.isLinkActive = function () {\n\t\n\t var isActive = false;\n\t\n\t editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\n\t\n\t var dataType = tool.dataset.type;\n\t\n\t if (dataType == 'link' && tool.classList.contains('hightlighted')) {\n\t\n\t isActive = true;\n\t }\n\t });\n\t\n\t return isActive;\n\t };\n\t\n\t /** default action behavior of tool */\n\t inline.defaultToolAction = function (type) {\n\t\n\t document.execCommand(type, false, null);\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Sets URL\n\t *\n\t * @param {String} url - URL\n\t */\n\t inline.setAnchor = function (url) {\n\t\n\t document.execCommand('createLink', false, url);\n\t\n\t /** Close after URL inserting */\n\t editor.toolbar.inline.closeAction();\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Saves selection\n\t */\n\t inline.saveSelection = function (containerEl) {\n\t\n\t var range = window.getSelection().getRangeAt(0),\n\t preSelectionRange = range.cloneRange(),\n\t start;\n\t\n\t preSelectionRange.selectNodeContents(containerEl);\n\t preSelectionRange.setEnd(range.startContainer, range.startOffset);\n\t\n\t start = preSelectionRange.toString().length;\n\t\n\t return {\n\t start: start,\n\t end: start + range.toString().length\n\t };\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Sets to previous selection (Range)\n\t *\n\t * @param {Element} containerEl - editable element where we restore range\n\t * @param {Object} savedSel - range basic information to restore\n\t */\n\t inline.restoreSelection = function (containerEl, savedSel) {\n\t\n\t var range = document.createRange(),\n\t charIndex = 0;\n\t\n\t range.setStart(containerEl, 0);\n\t range.collapse(true);\n\t\n\t var nodeStack = [containerEl],\n\t node,\n\t foundStart = false,\n\t stop = false,\n\t nextCharIndex;\n\t\n\t while (!stop && (node = nodeStack.pop())) {\n\t\n\t if (node.nodeType == 3) {\n\t\n\t nextCharIndex = charIndex + node.length;\n\t\n\t if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\n\t\n\t range.setStart(node, savedSel.start - charIndex);\n\t foundStart = true;\n\t }\n\t if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\n\t\n\t range.setEnd(node, savedSel.end - charIndex);\n\t stop = true;\n\t }\n\t charIndex = nextCharIndex;\n\t } else {\n\t\n\t var i = node.childNodes.length;\n\t\n\t while (i--) {\n\t\n\t nodeStack.push(node.childNodes[i]);\n\t }\n\t }\n\t }\n\t\n\t var sel = window.getSelection();\n\t\n\t sel.removeAllRanges();\n\t sel.addRange(range);\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Removes all ranges from window selection\n\t */\n\t inline.clearRange = function () {\n\t\n\t var selection = window.getSelection();\n\t\n\t selection.removeAllRanges();\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * sets or removes hightlight\n\t */\n\t inline.hightlight = function (tool) {\n\t\n\t var dataType = tool.dataset.type;\n\t\n\t if (document.queryCommandState(dataType)) {\n\t\n\t editor.toolbar.inline.setButtonHighlighted(tool);\n\t } else {\n\t\n\t editor.toolbar.inline.removeButtonsHighLight(tool);\n\t }\n\t\n\t /**\n\t *\n\t * hightlight for anchors\n\t */\n\t var selection = window.getSelection(),\n\t tag = selection.anchorNode.parentNode;\n\t\n\t if (tag.tagName == 'A' && dataType == 'link') {\n\t\n\t editor.toolbar.inline.setButtonHighlighted(tool);\n\t }\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Mark button if text is already executed\n\t */\n\t inline.setButtonHighlighted = function (button) {\n\t\n\t button.classList.add('hightlighted');\n\t\n\t /** At link tool we also change icon */\n\t if (button.dataset.type == 'link') {\n\t\n\t var icon = button.childNodes[0];\n\t\n\t icon.classList.remove('ce-icon-link');\n\t icon.classList.add('ce-icon-unlink');\n\t }\n\t };\n\t\n\t /**\n\t * @private\n\t *\n\t * Removes hightlight\n\t */\n\t inline.removeButtonsHighLight = function (button) {\n\t\n\t button.classList.remove('hightlighted');\n\t\n\t /** At link tool we also change icon */\n\t if (button.dataset.type == 'link') {\n\t\n\t var icon = button.childNodes[0];\n\t\n\t icon.classList.remove('ce-icon-unlink');\n\t icon.classList.add('ce-icon-link');\n\t }\n\t };\n\t\n\t return inline;\n\t}({});\n\n/***/ },\n/* 11 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor toolbox\n\t *\n\t * All tools be able to appended here\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (toolbox) {\n\t\n\t var editor = codex.editor;\n\t\n\t toolbox.opened = false;\n\t\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 editor.toolbar.current = null;\n\t };\n\t\n\t toolbox.leaf = function () {\n\t\n\t var currentTool = editor.toolbar.current,\n\t tools = Object.keys(editor.tools),\n\t barButtons = editor.nodes.toolbarButtons,\n\t nextToolIndex = 0,\n\t toolToSelect = void 0,\n\t visibleTool = void 0,\n\t tool = void 0;\n\t\n\t if (!currentTool) {\n\t\n\t /** Get first tool from object*/\n\t for (tool in editor.tools) {\n\t\n\t if (editor.tools[tool].displayInToolbox) {\n\t\n\t break;\n\t }\n\t\n\t nextToolIndex++;\n\t }\n\t } else {\n\t\n\t nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;\n\t visibleTool = tools[nextToolIndex];\n\t\n\t while (!editor.tools[visibleTool].displayInToolbox) {\n\t\n\t nextToolIndex = (nextToolIndex + 1) % tools.length;\n\t visibleTool = tools[nextToolIndex];\n\t }\n\t }\n\t\n\t toolToSelect = tools[nextToolIndex];\n\t\n\t for (var button in barButtons) {\n\t\n\t barButtons[button].classList.remove('selected');\n\t }\n\t\n\t barButtons[toolToSelect].classList.add('selected');\n\t editor.toolbar.current = toolToSelect;\n\t };\n\t\n\t /**\n\t * Transforming selected node type into selected toolbar element type\n\t * @param {event} event\n\t */\n\t toolbox.toolClicked = function (event) {\n\t\n\t /**\n\t * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty\n\t */\n\t var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],\n\t tool = editor.tools[editor.toolbar.current],\n\t workingNode = editor.content.currentNode,\n\t currentInputIndex = editor.caret.inputIndex,\n\t newBlockContent,\n\t appendCallback,\n\t blockData;\n\t\n\t /** Make block from plugin */\n\t newBlockContent = tool.render();\n\t\n\t /** information about block */\n\t blockData = {\n\t block: newBlockContent,\n\t type: tool.type,\n\t stretched: false\n\t };\n\t\n\t if (workingNode && UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 && workingNode.textContent.trim() === '') {\n\t\n\t /** Replace current block */\n\t editor.content.switchBlock(workingNode, newBlockContent, tool.type);\n\t } else {\n\t\n\t /** Insert new Block from plugin */\n\t editor.content.insertBlock(blockData);\n\t\n\t /** increase input index */\n\t currentInputIndex++;\n\t }\n\t\n\t /** Fire tool append callback */\n\t appendCallback = tool.appendCallback;\n\t\n\t if (appendCallback && typeof appendCallback == 'function') {\n\t\n\t appendCallback.call(event);\n\t }\n\t\n\t window.setTimeout(function () {\n\t\n\t /** Set caret to current block */\n\t editor.caret.setToBlock(currentInputIndex);\n\t }, 10);\n\t\n\t /**\n\t * Changing current Node\n\t */\n\t editor.content.workingNodeChanged();\n\t\n\t /**\n\t * Move toolbar when node is changed\n\t */\n\t editor.toolbar.move();\n\t };\n\t\n\t return toolbox;\n\t}({});\n\n/***/ },\n/* 12 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor callbacks module\n\t *\n\t * @author Codex Team\n\t * @version 1.3.10\n\t */\n\t\n\tmodule.exports = function (callbacks) {\n\t\n\t var editor = codex.editor;\n\t\n\t callbacks.globalKeydown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.redactorKeyDown = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.TAB:\n\t editor.callback.tabKeyPressed(event);break;\n\t case editor.core.keys.ENTER:\n\t editor.callback.enterKeyPressedOnRedactorZone(event);break;\n\t case editor.core.keys.ESC:\n\t editor.callback.escapeKeyPressed(event);break;\n\t default:\n\t editor.callback.defaultKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.globalKeyup = function (event) {\n\t\n\t switch (event.keyCode) {\n\t case editor.core.keys.UP:\n\t case editor.core.keys.LEFT:\n\t case editor.core.keys.RIGHT:\n\t case editor.core.keys.DOWN:\n\t editor.callback.arrowKeyPressed(event);break;\n\t }\n\t };\n\t\n\t callbacks.tabKeyPressed = function (event) {\n\t\n\t var inputs = editor.content.currentNode.querySelectorAll('textarea, input'),\n\t inputsAreEmpty = true,\n\t textContentIsEmpty = !editor.content.currentNode.textContent.trim();\n\t\n\t Array.prototype.map.call(inputs, function (input) {\n\t\n\t if (input.type == 'textarea' || input.type == 'text') {\n\t\n\t inputsAreEmpty = inputsAreEmpty && !input.value.trim();\n\t }\n\t });\n\t\n\t var blockIsEmpty = textContentIsEmpty && inputsAreEmpty;\n\t\n\t if (!blockIsEmpty) {\n\t\n\t return;\n\t }\n\t\n\t if (!editor.toolbar.opened) {\n\t\n\t editor.toolbar.open();\n\t }\n\t\n\t if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\t\n\t editor.toolbar.toolbox.open();\n\t } else {\n\t\n\t editor.toolbar.toolbox.leaf();\n\t }\n\t\n\t event.preventDefault();\n\t };\n\t\n\t /**\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

    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 if (!inputIsEmpty) {\n\t\n\t /** Mark current block */\n\t editor.content.markBlock();\n\t }\n\t\n\t if (isInitialType && inputIsEmpty) {\n\t\n\t /** Show plus button */\n\t editor.toolbar.showPlusButton();\n\t }\n\t };\n\t\n\t /**\n\t * This method allows to define, is caret in contenteditable element or not.\n\t * 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 (isNativeInput(event.target)) {\n\t\n\t /** If input value is empty - remove block */\n\t if (event.target.value.trim() == '') {\n\t\n\t block.remove();\n\t } else {\n\t\n\t return;\n\t }\n\t }\n\t\n\t if (block.textContent.trim()) {\n\t\n\t range = editor.content.getRange();\n\t selectionLength = range.endOffset - range.startOffset;\n\t\n\t if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {\n\t\n\t editor.content.mergeBlocks(currentInputIndex);\n\t } else {\n\t\n\t return;\n\t }\n\t }\n\t\n\t if (!selectionLength) {\n\t\n\t block.remove();\n\t }\n\t\n\t firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\t\n\t /**\n\t * If all blocks are removed\n\t */\n\t if (firstLevelBlocksCount === 0) {\n\t\n\t /** update currentNode variable */\n\t editor.content.currentNode = null;\n\t\n\t /** Inserting new empty initial block */\n\t editor.ui.addInitialBlock();\n\t\n\t /** Updating inputs state after deleting last block */\n\t editor.ui.saveInputs();\n\t\n\t /** Set to current appended block */\n\t window.setTimeout(function () {\n\t\n\t editor.caret.setToPreviousBlock(1);\n\t }, 10);\n\t } else {\n\t\n\t if (editor.caret.inputIndex !== 0) {\n\t\n\t /** Target block is not first */\n\t editor.caret.setToPreviousBlock(editor.caret.inputIndex);\n\t } else {\n\t\n\t /** If we try to delete first block */\n\t editor.caret.setToNextBlock(editor.caret.inputIndex);\n\t }\n\t }\n\t\n\t editor.toolbar.move();\n\t\n\t if (!editor.toolbar.opened) {\n\t\n\t editor.toolbar.open();\n\t }\n\t\n\t /** Updating inputs state */\n\t editor.ui.saveInputs();\n\t\n\t /** Prevent default browser behaviour */\n\t event.preventDefault();\n\t };\n\t\n\t /**\n\t * 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 /** If area is input or textarea then allow default behaviour */\n\t if (isNativeInput(event.target)) {\n\t\n\t return;\n\t }\n\t\n\t /** Prevent default behaviour */\n\t event.preventDefault();\n\t\n\t var editableParent = editor.content.getEditableParent(event.target),\n\t currentNode = editor.content.currentNode;\n\t\n\t /** Allow paste when event target placed in Editable element */\n\t if (!editableParent) {\n\t\n\t return;\n\t }\n\t\n\t /** get html pasted data - dirty data */\n\t var htmlData = event.clipboardData.getData('text/html'),\n\t plainData = event.clipboardData.getData('text/plain');\n\t\n\t /** Temporary DIV that is used to work with 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 if (htmlData.trim() != '') {\n\t\n\t cleanData = cleaner.clean(htmlData);\n\t div.innerHTML = cleanData;\n\t } else {\n\t\n\t div.innerText = plainData.toString();\n\t }\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 if (editor.tools[currentNode.dataset.tool].allowRenderOnPaste) {\n\t\n\t if (editor.paste.pasted(event)) return;\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 /**\n\t * Check block for\n\t * @param target\n\t */\n\t var isNativeInput = function isNativeInput(target) {\n\t\n\t var nativeInputAreas = ['INPUT', 'TEXTAREA'];\n\t\n\t return nativeInputAreas.indexOf(target.tagName) != -1;\n\t };\n\t\n\t return callbacks;\n\t}({});\n\n/***/ },\n/* 13 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Draw module\n\t *\n\t * @author Codex Team\n\t * @version 1.0.\n\t */\n\t\n\tmodule.exports = function (draw) {\n\t\n\t /**\n\t * Base editor wrapper\n\t */\n\t draw.wrapper = function () {\n\t\n\t var wrapper = document.createElement('div');\n\t\n\t wrapper.className += 'codex-editor';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * Content-editable holder\n\t */\n\t draw.redactor = function () {\n\t\n\t var redactor = document.createElement('div');\n\t\n\t redactor.className += 'ce-redactor';\n\t\n\t return redactor;\n\t };\n\t\n\t draw.ceBlock = function () {\n\t\n\t var block = document.createElement('DIV');\n\t\n\t block.className += 'ce_block';\n\t\n\t return block;\n\t };\n\t\n\t /**\n\t * Empty toolbar with toggler\n\t */\n\t draw.toolbar = function () {\n\t\n\t var bar = document.createElement('div');\n\t\n\t bar.className += 'ce-toolbar';\n\t\n\t return bar;\n\t };\n\t\n\t draw.toolbarContent = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.classList.add('ce-toolbar__content');\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * Inline toolbar\n\t */\n\t draw.inlineToolbar = function () {\n\t\n\t var bar = document.createElement('DIV');\n\t\n\t bar.className += 'ce-toolbar-inline';\n\t\n\t return bar;\n\t };\n\t\n\t /**\n\t * Wrapper for inline toobar buttons\n\t */\n\t draw.inlineToolbarButtons = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.className += 'ce-toolbar-inline__buttons';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * For some actions\n\t */\n\t draw.inlineToolbarActions = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.className += 'ce-toolbar-inline__actions';\n\t\n\t return wrapper;\n\t };\n\t\n\t draw.inputForLink = function () {\n\t\n\t var input = document.createElement('INPUT');\n\t\n\t input.type = 'input';\n\t input.className += 'inputForLink';\n\t input.placeholder = 'Вставьте ссылку ...';\n\t input.setAttribute('form', 'defaultForm');\n\t\n\t input.setAttribute('autofocus', 'autofocus');\n\t\n\t return input;\n\t };\n\t\n\t /**\n\t * @todo Desc\n\t */\n\t draw.blockButtons = function () {\n\t\n\t var block = document.createElement('div');\n\t\n\t block.className += 'ce-toolbar__actions';\n\t\n\t return block;\n\t };\n\t\n\t /**\n\t * Block settings panel\n\t */\n\t draw.blockSettings = function () {\n\t\n\t var settings = document.createElement('div');\n\t\n\t settings.className += 'ce-settings';\n\t\n\t return settings;\n\t };\n\t\n\t draw.defaultSettings = function () {\n\t\n\t var div = document.createElement('div');\n\t\n\t div.classList.add('ce-settings_default');\n\t\n\t return div;\n\t };\n\t\n\t draw.pluginsSettings = function () {\n\t\n\t var div = document.createElement('div');\n\t\n\t div.classList.add('ce-settings_plugin');\n\t\n\t return div;\n\t };\n\t\n\t draw.plusButton = function () {\n\t\n\t var button = document.createElement('span');\n\t\n\t button.className = 'ce-toolbar__plus';\n\t // button.innerHTML = '';\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 = '';\n\t\n\t return toggler;\n\t };\n\t\n\t /**\n\t * Redactor tools wrapper\n\t */\n\t\n\t draw.toolbox = function () {\n\t\n\t var wrapper = document.createElement('div');\n\t\n\t wrapper.className = 'ce-toolbar__tools';\n\t\n\t return wrapper;\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Draws tool buttons for toolbox\n\t *\n\t * @param {String} type\n\t * @param {String} classname\n\t * @returns {Element}\n\t */\n\t draw.toolbarButton = function (type, classname) {\n\t\n\t var button = document.createElement('li'),\n\t toolIcon = document.createElement('i'),\n\t toolTitle = document.createElement('span');\n\t\n\t button.dataset.type = type;\n\t button.setAttribute('title', type);\n\t\n\t toolIcon.classList.add(classname);\n\t toolTitle.classList.add('ce_toolbar_tools--title');\n\t\n\t button.appendChild(toolIcon);\n\t button.appendChild(toolTitle);\n\t\n\t return button;\n\t };\n\t\n\t /**\n\t * @protected\n\t *\n\t * Draws tools for inline toolbar\n\t *\n\t * @param {String} type\n\t * @param {String} classname\n\t */\n\t draw.toolbarButtonInline = function (type, classname) {\n\t\n\t var button = document.createElement('BUTTON'),\n\t toolIcon = document.createElement('I');\n\t\n\t button.type = 'button';\n\t button.dataset.type = type;\n\t toolIcon.classList.add(classname);\n\t\n\t button.appendChild(toolIcon);\n\t\n\t return button;\n\t };\n\t\n\t /**\n\t * Redactor block\n\t */\n\t draw.block = function (tagName, content) {\n\t\n\t var node = document.createElement(tagName);\n\t\n\t node.innerHTML = content || '';\n\t\n\t return node;\n\t };\n\t\n\t /**\n\t * Creates Node with passed tagName and className\n\t * @param {string} tagName\n\t * @param {string} className\n\t * @param {object} properties - allow to assign properties\n\t */\n\t draw.node = function (tagName, className, properties) {\n\t\n\t var el = document.createElement(tagName);\n\t\n\t if (className) el.className = className;\n\t\n\t if (properties) {\n\t\n\t for (var name in properties) {\n\t\n\t el[name] = properties[name];\n\t }\n\t }\n\t\n\t return el;\n\t };\n\t\n\t /**\n\t * Unavailable plugin block\n\t */\n\t draw.unavailableBlock = function () {\n\t\n\t var wrapper = document.createElement('DIV');\n\t\n\t wrapper.classList.add('cdx-unavailable-block');\n\t\n\t return wrapper;\n\t };\n\t\n\t return draw;\n\t}({});\n\n/***/ },\n/* 14 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Caret Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (caret) {\n\t\n\t var editor = codex.editor;\n\t\n\t /**\n\t * @var {int} InputIndex - editable element in DOM\n\t */\n\t caret.inputIndex = null;\n\t\n\t /**\n\t * @var {int} offset - caret position in a text node.\n\t */\n\t caret.offset = null;\n\t\n\t /**\n\t * @var {int} focusedNodeIndex - we get index of child node from first-level block\n\t */\n\t caret.focusedNodeIndex = null;\n\t\n\t /**\n\t * Creates Document Range and sets caret to the element.\n\t * @protected\n\t * @uses caret.save — if you need to save caret position\n\t * @param {Element} el - Changed Node.\n\t */\n\t caret.set = function (el, index, offset) {\n\t\n\t offset = offset || caret.offset || 0;\n\t index = index || caret.focusedNodeIndex || 0;\n\t\n\t var childs = el.childNodes,\n\t nodeToSet;\n\t\n\t if (childs.length === 0) {\n\t\n\t nodeToSet = el;\n\t } else {\n\t\n\t nodeToSet = childs[index];\n\t }\n\t\n\t /** If Element is INPUT */\n\t if (el.contentEditable != 'true') {\n\t\n\t el.focus();\n\t return;\n\t }\n\t\n\t if (editor.core.isDomNode(nodeToSet)) {\n\t\n\t nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);\n\t }\n\t\n\t var range = document.createRange(),\n\t selection = window.getSelection();\n\t\n\t window.setTimeout(function () {\n\t\n\t range.setStart(nodeToSet, offset);\n\t range.setEnd(nodeToSet, offset);\n\t\n\t selection.removeAllRanges();\n\t selection.addRange(range);\n\t\n\t editor.caret.saveCurrentInputIndex();\n\t }, 20);\n\t };\n\t\n\t /**\n\t * @protected\n\t * Updates index of input and saves it in caret object\n\t */\n\t caret.saveCurrentInputIndex = function () {\n\t\n\t /** Index of Input that we paste sanitized content */\n\t var selection = window.getSelection(),\n\t inputs = editor.state.inputs,\n\t focusedNode = selection.anchorNode,\n\t focusedNodeHolder;\n\t\n\t if (!focusedNode) {\n\t\n\t return;\n\t }\n\t\n\t /** Looking for parent contentEditable block */\n\t while (focusedNode.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/* 15 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Notification Module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (notifications) {\n\t\n\t var editor = codex.editor;\n\t\n\t var queue = [];\n\t\n\t var addToQueue = function addToQueue(settings) {\n\t\n\t queue.push(settings);\n\t\n\t var index = 0;\n\t\n\t while (index < queue.length && queue.length > 5) {\n\t\n\t if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n\t\n\t index++;\n\t continue;\n\t }\n\t\n\t queue[index].close();\n\t queue.splice(index, 1);\n\t }\n\t };\n\t\n\t notifications.createHolder = function () {\n\t\n\t var holder = editor.draw.node('DIV', 'cdx-notifications-block');\n\t\n\t editor.nodes.notifications = document.body.appendChild(holder);\n\t\n\t return holder;\n\t };\n\t\n\t /**\n\t * Error notificator. Shows block with message\n\t * @protected\n\t */\n\t notifications.errorThrown = function (errorMsg, event) {\n\t\n\t editor.notifications.notification({ message: 'This action is not available currently', type: event.type });\n\t };\n\t\n\t /**\n\t *\n\t * Appends notification\n\t *\n\t * settings = {\n\t * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\n\t * message - notification message\n\t * okMsg - confirm button text (default - 'Ok')\n\t * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\n\t * confirm - function-handler for ok button click\n\t * cancel - function-handler for cancel button click. Only for confirm and prompt types\n\t * time - time (in seconds) after which notification will close (default - 10s)\n\t * }\n\t *\n\t * @param settings\n\t */\n\t notifications.notification = function (constructorSettings) {\n\t\n\t /** Private vars and methods */\n\t var notification = null,\n\t cancel = null,\n\t type = null,\n\t confirm = null,\n\t inputField = null;\n\t\n\t var confirmHandler = function confirmHandler() {\n\t\n\t close();\n\t\n\t if (typeof confirm !== 'function') {\n\t\n\t return;\n\t }\n\t\n\t if (type == 'prompt') {\n\t\n\t confirm(inputField.value);\n\t return;\n\t }\n\t\n\t confirm();\n\t };\n\t\n\t var cancelHandler = function cancelHandler() {\n\t\n\t close();\n\t\n\t if (typeof cancel !== 'function') {\n\t\n\t return;\n\t }\n\t\n\t cancel();\n\t };\n\t\n\t /** Public methods */\n\t function create(settings) {\n\t\n\t if (!(settings && settings.message)) {\n\t\n\t editor.core.log('Can\\'t create notification. Message is missed');\n\t return;\n\t }\n\t\n\t settings.type = settings.type || 'alert';\n\t settings.time = settings.time * 1000 || 10000;\n\t\n\t var wrapper = editor.draw.node('DIV', 'cdx-notification'),\n\t message = editor.draw.node('DIV', 'cdx-notification__message'),\n\t input = editor.draw.node('INPUT', 'cdx-notification__input'),\n\t okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\n\t cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\n\t\n\t message.textContent = settings.message;\n\t okBtn.textContent = settings.okMsg || 'ОК';\n\t cancelBtn.textContent = settings.cancelMsg || 'Отмена';\n\t\n\t editor.listeners.add(okBtn, 'click', confirmHandler);\n\t editor.listeners.add(cancelBtn, 'click', cancelHandler);\n\t\n\t wrapper.appendChild(message);\n\t\n\t if (settings.type == 'prompt') {\n\t\n\t wrapper.appendChild(input);\n\t }\n\t\n\t wrapper.appendChild(okBtn);\n\t\n\t if (settings.type == 'prompt' || settings.type == 'confirm') {\n\t\n\t wrapper.appendChild(cancelBtn);\n\t }\n\t\n\t wrapper.classList.add('cdx-notification-' + settings.type);\n\t wrapper.dataset.type = settings.type;\n\t\n\t notification = wrapper;\n\t type = settings.type;\n\t confirm = settings.confirm;\n\t cancel = settings.cancel;\n\t inputField = input;\n\t\n\t if (settings.type != 'prompt' && settings.type != 'confirm') {\n\t\n\t window.setTimeout(close, settings.time);\n\t }\n\t };\n\t\n\t function send() {\n\t\n\t editor.nodes.notifications.appendChild(notification);\n\t inputField.focus();\n\t\n\t editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\n\t\n\t window.setTimeout(function () {\n\t\n\t editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n\t }, 100);\n\t\n\t addToQueue({ type: type, close: close });\n\t };\n\t\n\t function close() {\n\t\n\t notification.remove();\n\t };\n\t\n\t if (constructorSettings) {\n\t\n\t create(constructorSettings);\n\t send();\n\t }\n\t\n\t return {\n\t create: create,\n\t send: send,\n\t close: close\n\t };\n\t };\n\t\n\t notifications.clear = function () {\n\t\n\t editor.nodes.notifications.innerHTML = '';\n\t queue = [];\n\t };\n\t\n\t return notifications;\n\t}({});\n\n/***/ },\n/* 16 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\t/**\n\t * Codex Editor Parser Module\n\t *\n\t * @author Codex Team\n\t * @version 1.1\n\t */\n\t\n\tmodule.exports = function (parser) {\n\t\n\t var editor = codex.editor;\n\t\n\t /** inserting text */\n\t parser.insertPastedContent = function (blockType, tag) {\n\t\n\t editor.content.insertBlock({\n\t type: blockType.type,\n\t block: blockType.render({\n\t text: tag.innerHTML\n\t })\n\t });\n\t };\n\t\n\t /**\n\t * Check DOM node for display style: separated block or child-view\n\t */\n\t parser.isFirstLevelBlock = function (node) {\n\t\n\t return node.nodeType == editor.core.nodeTypes.TAG && node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n\t };\n\t\n\t return parser;\n\t}({});\n\n/***/ },\n/* 17 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Sanitizer\n\t */\n\t\n\tmodule.exports = function (sanitizer) {\n\t\n\t var janitor = __webpack_require__(18);\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/* 18 */\n/***/ function(module, exports, __webpack_require__) {\n\n\tvar __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory) {\n\t if (true) {\n\t !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t } else if (typeof exports === 'object') {\n\t module.exports = factory();\n\t } else {\n\t root.HTMLJanitor = factory();\n\t }\n\t}(this, function () {\n\t\n\t /**\n\t * @param {Object} config.tags Dictionary of allowed tags.\n\t * @param {boolean} config.keepNestedBlockElements Default false.\n\t */\n\t function HTMLJanitor(config) {\n\t\n\t var tagDefinitions = config['tags'];\n\t var tags = Object.keys(tagDefinitions);\n\t\n\t var validConfigValues = tags\n\t .map(function(k) { return typeof tagDefinitions[k]; })\n\t .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; });\n\t\n\t if(!validConfigValues) {\n\t throw new Error(\"The configuration was invalid\");\n\t }\n\t\n\t this.config = config;\n\t }\n\t\n\t // TODO: not exhaustive?\n\t var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE'];\n\t function isBlockElement(node) {\n\t return blockElementNames.indexOf(node.nodeName) !== -1;\n\t }\n\t\n\t var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE'];\n\t function isInlineElement(node) {\n\t return inlineElementNames.indexOf(node.nodeName) !== -1;\n\t }\n\t\n\t HTMLJanitor.prototype.clean = function (html) {\n\t var sandbox = document.createElement('div');\n\t sandbox.innerHTML = html;\n\t\n\t this._sanitize(sandbox);\n\t\n\t return sandbox.innerHTML;\n\t };\n\t\n\t HTMLJanitor.prototype._sanitize = function (parentNode) {\n\t var treeWalker = createTreeWalker(parentNode);\n\t var node = treeWalker.firstChild();\n\t if (!node) { return; }\n\t\n\t do {\n\t // Ignore nodes that have already been sanitized\n\t if (node._sanitized) {\n\t continue;\n\t }\n\t\n\t if (node.nodeType === Node.TEXT_NODE) {\n\t // If this text node is just whitespace and the previous or next element\n\t // sibling is a block element, remove it\n\t // N.B.: This heuristic could change. Very specific to a bug with\n\t // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output\n\t // FIXME: make this an option?\n\t if (node.data.trim() === ''\n\t && ((node.previousElementSibling && isBlockElement(node.previousElementSibling))\n\t || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) {\n\t parentNode.removeChild(node);\n\t this._sanitize(parentNode);\n\t break;\n\t } else {\n\t continue;\n\t }\n\t }\n\t\n\t // Remove all comments\n\t if (node.nodeType === Node.COMMENT_NODE) {\n\t parentNode.removeChild(node);\n\t this._sanitize(parentNode);\n\t break;\n\t }\n\t\n\t var isInline = isInlineElement(node);\n\t var containsBlockElement;\n\t if (isInline) {\n\t containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement);\n\t }\n\t\n\t // Block elements should not be nested (e.g.

  • ...); if\n\t // they are, we want to unwrap the inner block element.\n\t var isNotTopContainer = !! parentNode.parentNode;\n\t var isNestedBlockElement =\n\t isBlockElement(parentNode) &&\n\t isBlockElement(node) &&\n\t isNotTopContainer;\n\t\n\t var nodeName = node.nodeName.toLowerCase();\n\t\n\t var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\t\n\t var isInvalid = isInline && containsBlockElement;\n\t\n\t // Drop tag entirely according to the whitelist *and* if the markup\n\t // is invalid.\n\t if (isInvalid || shouldRejectNode(node, allowedAttrs)\n\t || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n\t // Do not keep the inner text of SCRIPT/STYLE elements.\n\t if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n\t while (node.childNodes.length > 0) {\n\t parentNode.insertBefore(node.childNodes[0], node);\n\t }\n\t }\n\t parentNode.removeChild(node);\n\t\n\t this._sanitize(parentNode);\n\t break;\n\t }\n\t\n\t // Sanitize attributes\n\t for (var a = 0; a < node.attributes.length; a += 1) {\n\t var attr = node.attributes[a];\n\t\n\t if (shouldRejectAttr(attr, allowedAttrs, node)) {\n\t node.removeAttribute(attr.name);\n\t // Shift the array to continue looping.\n\t a = a - 1;\n\t }\n\t }\n\t\n\t // Sanitize children\n\t this._sanitize(node);\n\t\n\t // Mark node as sanitized so it's ignored in future runs\n\t node._sanitized = true;\n\t } while ((node = treeWalker.nextSibling()));\n\t };\n\t\n\t function createTreeWalker(node) {\n\t return document.createTreeWalker(node,\n\t NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n\t null, false);\n\t }\n\t\n\t function getAllowedAttrs(config, nodeName, node){\n\t if (typeof config.tags[nodeName] === 'function') {\n\t return config.tags[nodeName](node);\n\t } else {\n\t return config.tags[nodeName];\n\t }\n\t }\n\t\n\t function shouldRejectNode(node, allowedAttrs){\n\t if (typeof allowedAttrs === 'undefined') {\n\t return true;\n\t } else if (typeof allowedAttrs === 'boolean') {\n\t return !allowedAttrs;\n\t }\n\t\n\t return false;\n\t }\n\t\n\t function shouldRejectAttr(attr, allowedAttrs, node){\n\t var attrName = attr.name.toLowerCase();\n\t\n\t if (allowedAttrs === true){\n\t return false;\n\t } else if (typeof allowedAttrs[attrName] === 'function'){\n\t return !allowedAttrs[attrName](attr.value, node);\n\t } else if (typeof allowedAttrs[attrName] === 'undefined'){\n\t return true;\n\t } else if (allowedAttrs[attrName] === false) {\n\t return true;\n\t } else if (typeof allowedAttrs[attrName] === 'string') {\n\t return (allowedAttrs[attrName] !== attr.value);\n\t }\n\t\n\t return false;\n\t }\n\t\n\t return HTMLJanitor;\n\t\n\t}));\n\n\n/***/ },\n/* 19 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Anchors module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (anchors) {\n\t\n\t var editor = codex.editor;\n\t\n\t anchors.input = null;\n\t anchors.currentNode = null;\n\t\n\t anchors.settingsOpened = function (currentBlock) {\n\t\n\t anchors.currentNode = currentBlock;\n\t anchors.input.value = anchors.currentNode.dataset.anchor || '';\n\t };\n\t\n\t anchors.anchorChanged = function (e) {\n\t\n\t var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);\n\t\n\t anchors.currentNode.dataset.anchor = newAnchor;\n\t\n\t if (newAnchor.trim() !== '') {\n\t\n\t anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t } else {\n\t\n\t anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);\n\t }\n\t };\n\t\n\t anchors.keyDownOnAnchorInput = function (e) {\n\t\n\t if (e.keyCode == editor.core.keys.ENTER) {\n\t\n\t e.preventDefault();\n\t e.stopPropagation();\n\t\n\t e.target.blur();\n\t editor.toolbar.settings.close();\n\t }\n\t };\n\t\n\t anchors.keyUpOnAnchorInput = function (e) {\n\t\n\t if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {\n\t\n\t e.stopPropagation();\n\t }\n\t };\n\t\n\t anchors.rusToTranslit = function (string) {\n\t\n\t var ru = ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'],\n\t en = ['A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya'];\n\t\n\t for (var i = 0; i < ru.length; i++) {\n\t\n\t string = string.split(ru[i]).join(en[i]);\n\t string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());\n\t }\n\t\n\t string = string.replace(/[^0-9a-zA-Z_]+/g, '-');\n\t\n\t return string;\n\t };\n\t\n\t return anchors;\n\t}({});\n\n/***/ },\n/* 20 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\t/**\n\t * Codex Editor Listeners module\n\t *\n\t * @author Codex Team\n\t * @version 1.0\n\t */\n\t\n\t/**\n\t * Module-decorator for event listeners assignment\n\t */\n\tmodule.exports = function (listeners) {\n\t\n\t var allListeners = [];\n\t\n\t /**\n\t * Search methods\n\t *\n\t * byElement, byType and byHandler returns array of suitable listeners\n\t * one and all takes element, eventType, and handler and returns first (all) suitable listener\n\t *\n\t */\n\t listeners.search = function () {\n\t\n\t var byElement = function byElement(element, context) {\n\t\n\t var listenersOnElement = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.element === element) {\n\t\n\t listenersOnElement.push(listener);\n\t }\n\t }\n\t\n\t return listenersOnElement;\n\t };\n\t\n\t var byType = function byType(eventType, context) {\n\t\n\t var listenersWithType = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.type === eventType) {\n\t\n\t listenersWithType.push(listener);\n\t }\n\t }\n\t\n\t return listenersWithType;\n\t };\n\t\n\t var byHandler = function byHandler(handler, context) {\n\t\n\t var listenersWithHandler = [];\n\t\n\t context = context || allListeners;\n\t\n\t for (var i = 0; i < context.length; i++) {\n\t\n\t var listener = context[i];\n\t\n\t if (listener.handler === handler) {\n\t\n\t listenersWithHandler.push(listener);\n\t }\n\t }\n\t\n\t return listenersWithHandler;\n\t };\n\t\n\t var one = function one(element, eventType, handler) {\n\t\n\t var result = allListeners;\n\t\n\t if (element) result = byElement(element, result);\n\t\n\t if (eventType) result = byType(eventType, result);\n\t\n\t if (handler) result = byHandler(handler, result);\n\t\n\t return result[0];\n\t };\n\t\n\t var all = function all(element, eventType, handler) {\n\t\n\t var result = allListeners;\n\t\n\t if (element) result = byElement(element, result);\n\t\n\t if (eventType) result = byType(eventType, result);\n\t\n\t if (handler) result = byHandler(handler, result);\n\t\n\t return result;\n\t };\n\t\n\t return {\n\t byElement: byElement,\n\t byType: byType,\n\t byHandler: byHandler,\n\t one: one,\n\t all: all\n\t };\n\t }();\n\t\n\t listeners.add = function (element, eventType, handler, isCapture) {\n\t\n\t element.addEventListener(eventType, handler, isCapture);\n\t\n\t var data = {\n\t element: element,\n\t type: eventType,\n\t handler: handler\n\t };\n\t\n\t var alreadyAddedListener = listeners.search.one(element, eventType, handler);\n\t\n\t if (!alreadyAddedListener) {\n\t\n\t allListeners.push(data);\n\t }\n\t };\n\t\n\t listeners.remove = function (element, eventType, handler) {\n\t\n\t element.removeEventListener(eventType, handler);\n\t\n\t var existingListeners = listeners.search.all(element, eventType, handler);\n\t\n\t for (var i = 0; i < existingListeners.length; i++) {\n\t\n\t var index = allListeners.indexOf(existingListeners[i]);\n\t\n\t if (index > 0) {\n\t\n\t allListeners.splice(index, 1);\n\t }\n\t }\n\t };\n\t\n\t listeners.removeAll = function () {\n\t\n\t allListeners.map(function (current) {\n\t\n\t listeners.remove(current.element, current.type, current.handler);\n\t });\n\t };\n\t\n\t listeners.get = function (element, eventType, handler) {\n\t\n\t return listeners.search.all(element, eventType, handler);\n\t };\n\t\n\t return listeners;\n\t}({});\n\n/***/ },\n/* 21 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; };\n\t\n\t/**\n\t * Codex Editor Destroyer module\n\t *\n\t * @auhor Codex Team\n\t * @version 1.0\n\t */\n\t\n\tmodule.exports = function (destroyer) {\n\t\n\t var editor = codex.editor;\n\t\n\t destroyer.removeNodes = function () {\n\t\n\t editor.nodes.wrapper.remove();\n\t editor.nodes.notifications.remove();\n\t };\n\t\n\t destroyer.destroyPlugins = function () {\n\t\n\t for (var tool in editor.tools) {\n\t\n\t if (typeof editor.tools[tool].destroy === 'function') {\n\t\n\t editor.tools[tool].destroy();\n\t }\n\t }\n\t };\n\t\n\t destroyer.destroyScripts = function () {\n\t\n\t var scripts = document.getElementsByTagName('SCRIPT');\n\t\n\t for (var i = 0; i < scripts.length; i++) {\n\t\n\t if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n\t\n\t scripts[i].remove();\n\t i--;\n\t }\n\t }\n\t };\n\t\n\t /**\n\t * Delete editor data from webpage.\n\t * You should send settings argument with boolean flags:\n\t * @param settings.ui- remove redactor event listeners and DOM nodes\n\t * @param settings.scripts - remove redactor scripts from DOM\n\t * @param settings.plugins - remove plugin's objects\n\t * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\n\t * }\n\t *\n\t */\n\t destroyer.destroy = function (settings) {\n\t\n\t if (!settings || (typeof settings === 'undefined' ? 'undefined' : _typeof(settings)) !== 'object') {\n\t\n\t return;\n\t }\n\t\n\t if (settings.ui) {\n\t\n\t destroyer.removeNodes();\n\t editor.listeners.removeAll();\n\t }\n\t\n\t if (settings.scripts) {\n\t\n\t destroyer.destroyScripts();\n\t }\n\t\n\t if (settings.plugins) {\n\t\n\t destroyer.destroyPlugins();\n\t }\n\t\n\t if (settings.ui && settings.scripts && settings.core) {\n\t\n\t delete codex.editor;\n\t }\n\t };\n\t\n\t return destroyer;\n\t}({});\n\n/***/ },\n/* 22 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/**\n\t * Codex Editor Paste module\n\t *\n\t * @author Codex Team\n\t * @version 1.1.1\n\t */\n\t\n\tmodule.exports = function (paste) {\n\t\n\t var editor = codex.editor;\n\t\n\t var patterns = [];\n\t\n\t paste.prepare = function () {\n\t\n\t var tools = editor.tools;\n\t\n\t for (var tool in tools) {\n\t\n\t if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n\t\n\t continue;\n\t }\n\t\n\t tools[tool].renderOnPastePatterns.map(function (pattern) {\n\t\n\t patterns.push(pattern);\n\t });\n\t }\n\t\n\t return Promise.resolve();\n\t };\n\t\n\t /**\n\t * Saves data\n\t * @param event\n\t */\n\t paste.pasted = function (event) {\n\t\n\t var clipBoardData = event.clipboardData || window.clipboardData,\n\t content = clipBoardData.getData('Text');\n\t\n\t var result = analize(content);\n\t\n\t if (result) {\n\t\n\t event.preventDefault();\n\t event.stopImmediatePropagation();\n\t }\n\t\n\t return result;\n\t };\n\t\n\t /**\n\t * Analizes pated string and calls necessary method\n\t */\n\t\n\t var analize = function analize(string) {\n\t\n\t var result = false,\n\t content = editor.content.currentNode,\n\t plugin = content.dataset.tool;\n\t\n\t patterns.map(function (pattern) {\n\t\n\t var execArray = pattern.regex.exec(string),\n\t match = execArray && execArray[0];\n\t\n\t if (match && match === string.trim()) {\n\t\n\t /** current block is not empty */\n\t if (content.textContent.trim() && plugin == editor.settings.initialBlockPlugin) {\n\t\n\t pasteToNewBlock_();\n\t }\n\t\n\t pattern.callback(string, pattern);\n\t result = true;\n\t }\n\t });\n\t\n\t return result;\n\t };\n\t\n\t var pasteToNewBlock_ = function pasteToNewBlock_() {\n\t\n\t /** Create new initial block */\n\t editor.content.insertBlock({\n\t\n\t type: editor.settings.initialBlockPlugin,\n\t block: editor.tools[editor.settings.initialBlockPlugin].render({\n\t text: ''\n\t })\n\t\n\t }, false);\n\t };\n\t\n\t return paste;\n\t}({});\n\n/***/ }\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// codex-editor.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap d53b65d3ebbd53c620c1","/**\n *\n * Codex Editor\n *\n * @author Codex Team\n */\n\nmodule.exports = (function (editor) {\n\n 'use strict';\n\n editor.version = VERSION;\n editor.scriptPrefix = 'cdx-script-';\n\n var init = function () {\n\n editor.core = require('./modules/core');\n editor.tools = require('./modules/tools');\n editor.ui = require('./modules/ui');\n editor.transport = require('./modules/transport');\n editor.renderer = require('./modules/renderer');\n editor.saver = require('./modules/saver');\n editor.content = require('./modules/content');\n editor.toolbar = require('./modules/toolbar/toolbar');\n editor.callback = require('./modules/callbacks');\n editor.draw = require('./modules/draw');\n editor.caret = require('./modules/caret');\n editor.notifications = require('./modules/notifications');\n editor.parser = require('./modules/parser');\n editor.sanitizer = require('./modules/sanitizer');\n editor.anchors = require('./modules/anchors');\n editor.listeners = require('./modules/listeners');\n editor.destroyer = require('./modules/destroyer');\n editor.paste = require('./modules/paste');\n\n };\n\n /**\n * @public\n *\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.tools.prepare)\n .then(editor.paste.prepare)\n .then(editor.transport.prepare)\n .then(editor.renderer.makeBlocksFromData)\n .then(editor.ui.saveInputs)\n .catch(function (error) {\n\n editor.core.log('Initialization failed with error: %o', 'warn', error);\n\n });\n\n };\n\n return editor;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./codex.js","/**\n * Codex Editor Core\n *\n * @author Codex Team\n * @version 1.1.2\n */\n\nmodule.exports = (function (core) {\n\n let editor = codex.editor;\n\n /**\n * @public\n *\n * Editor preparing method\n * @return Promise\n */\n core.prepare = function (userSettings) {\n\n return new Promise(function (resolve, reject) {\n\n if ( userSettings ) {\n\n editor.settings.tools = userSettings.tools || editor.settings.tools;\n\n }\n\n if (userSettings.data) {\n\n editor.state.blocks = userSettings.data;\n\n }\n\n if (userSettings.initialBlockPlugin) {\n\n editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\n\n }\n\n if (userSettings.uploadImagesUrl) {\n\n editor.settings.uploadImagesUrl = userSettings.uploadImagesUrl;\n\n }\n\n editor.hideToolbar = userSettings.hideToolbar;\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 * Checks passed object for emptiness\n * @require ES5 - Object.keys\n * @param {object}\n */\n core.isEmpty = function ( obj ) {\n\n return Object.keys(obj).length === 0;\n\n };\n\n /**\n * Native Ajax\n */\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 let script;\n\n /** Script is already loaded */\n if ( !instanceName ) {\n\n reject('Instance name is missed');\n\n } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) {\n\n resolve(scriptPath);\n\n }\n\n script = document.createElement('SCRIPT');\n script.async = true;\n script.defer = true;\n script.id = editor.scriptPrefix + instanceName;\n\n script.onload = function () {\n\n resolve(scriptPath);\n\n };\n\n script.onerror = function () {\n\n reject(scriptPath);\n\n };\n\n script.src = scriptPath;\n document.head.appendChild(script);\n\n });\n\n };\n\n return core;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/core.js","/**\n* Module working with plugins\n*/\nmodule.exports = (function () {\n\n let editor = codex.editor;\n\n /**\n * Initialize plugins before using\n * Ex. Load scripts or call some internal methods\n * @return Promise\n */\n function prepare() {\n\n return new Promise(function (resolve_, reject_) {\n\n Promise.resolve()\n\n /**\n * Compose a sequence of plugins that requires preparation\n */\n .then(function () {\n\n let pluginsRequiresPreparation = [],\n allPlugins = editor.tools;\n\n for ( let pluginName in allPlugins ) {\n\n let plugin = allPlugins[pluginName];\n\n if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {\n\n continue;\n\n }\n\n pluginsRequiresPreparation.push(plugin);\n\n }\n\n /**\n * If no one passed plugins requires preparation, finish prepare() and go ahead\n */\n if (!pluginsRequiresPreparation.length) {\n\n resolve_();\n\n }\n\n return pluginsRequiresPreparation;\n\n })\n\n /** Wait plugins while they prepares */\n .then(waitAllPluginsPreparation_)\n\n .then(function () {\n\n editor.core.log('Plugins loaded', 'info');\n resolve_();\n\n }).catch(function (error) {\n\n reject_(error);\n\n });\n\n });\n\n }\n\n /**\n * @param {array} plugins - list of tools that requires preparation\n * @return {Promise} resolved while all plugins will be ready or failed\n */\n function waitAllPluginsPreparation_(plugins) {\n\n /**\n * @calls allPluginsProcessed__ when all plugins prepared or failed\n */\n return new Promise (function (allPluginsProcessed__) {\n\n /**\n * pluck each element from queue\n * First, send resolved Promise as previous value\n * Each plugins \"prepare\" method returns a Promise, that's why\n * reduce current element will not be able to continue while can't get\n * a resolved Promise\n *\n * If last plugin is \"prepared\" then go to the next stage of initialization\n */\n plugins.reduce(function (previousValue, plugin, iteration) {\n\n return previousValue.then(function () {\n\n /**\n * Wait till plugins prepared\n * @calls pluginIsReady__ when plugin is ready or failed\n */\n return new Promise ( function (pluginIsReady__) {\n\n callPluginsPrepareMethod_( plugin )\n\n .then( pluginIsReady__ )\n .then( function () {\n\n plugin.available = true;\n\n })\n\n .catch(function (error) {\n\n editor.core.log(`Plugin «${plugin.type}» was not loaded. Preparation failed because %o`, 'warn', error);\n plugin.available = false;\n plugin.loadingMessage = error;\n\n /** Go ahead even some plugin has problems */\n pluginIsReady__();\n\n })\n\n .then(function () {\n\n /** If last plugin has problems then just ignore and continue */\n if (iteration == plugins.length - 1) {\n\n allPluginsProcessed__();\n\n }\n\n });\n\n });\n\n });\n\n }, Promise.resolve() );\n\n });\n\n }\n\n var callPluginsPrepareMethod_ = function (plugin) {\n\n return plugin.prepare( plugin.config || {} );\n\n };\n\n return {\n prepare: prepare\n };\n\n}());\n\n\n// WEBPACK FOOTER //\n// ./modules/tools.js","/**\n * Codex Editor UI module\n *\n * @author Codex Team\n * @version 1.1.3\n */\n\nmodule.exports = (function (ui) {\n\n let editor = codex.editor;\n\n /**\n * Basic editor classnames\n */\n ui.className = {\n\n /**\n * @const {string} BLOCK_CLASSNAME - redactor blocks name\n */\n BLOCK_CLASSNAME : 'ce-block',\n\n /**\n * @const {String} wrapper for plugins content\n */\n BLOCK_CONTENT : 'ce-block__content',\n\n /**\n * @const {String} BLOCK_STRETCHED - makes block stretched\n */\n BLOCK_STRETCHED : 'ce-block--stretched',\n\n /**\n * @const {String} BLOCK_HIGHLIGHTED - adds background\n */\n BLOCK_HIGHLIGHTED : 'ce-block--focused',\n\n /**\n * @const {String} - highlights covered blocks\n */\n BLOCK_IN_FEED_MODE : 'ce-block--feed-mode',\n\n /**\n * @const {String} - Block with anchor\n */\n BLOCK_WITH_ANCHOR : 'ce-block--anchor',\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 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 editor.notifications.createHolder();\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 && tool.displayInToolbox) {\n\n editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\n continue;\n\n }\n\n if (typeof tool.render != 'function') {\n\n editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\n continue;\n\n }\n\n if (!tool.displayInToolbox) {\n\n continue;\n\n } else {\n\n /** if tools is for toolbox */\n toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\n\n editor.nodes.toolbox.appendChild(toolButton);\n\n editor.nodes.toolbarButtons[toolName] = toolButton;\n\n }\n\n }\n\n /**\n * 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 editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n\n /** All keydowns on Redactor zone */\n editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n\n /** All keydowns on Document */\n editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );\n\n /**\n * Mouse click to radactor\n */\n editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );\n\n /**\n * Clicks to the Plus button\n */\n editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n\n /**\n * Clicks to SETTINGS button in toolbar\n */\n editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );\n\n /**\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.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n\n }\n\n };\n\n ui.addBlockHandlers = function (block) {\n\n if (!block) return;\n\n /**\n * Block keydowns\n */\n editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n\n /**\n * Pasting content from another source\n * We have two type of sanitization\n * First - uses deep-first search algorithm to get sub nodes,\n * sanitizes whole Block_content and replaces cleared nodes\n * This method is deprecated\n * Method is used in editor.callback.blockPaste(event)\n *\n * Secont - uses Mutation observer.\n * Observer \"observe\" DOM changes and send changings to callback.\n * Callback gets changed node, not whole Block_content.\n * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n *\n * Method is used in editor.callback.blockPasteViaSanitize(event)\n *\n * @uses html-janitor\n * @example editor.callback.blockPasteViaSanitize(event), the second method.\n *\n */\n editor.listeners.add(block, 'paste', editor.callback.blockPasteCallback, false);\n\n editor.listeners.add(block, '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 editor.state.inputs = [];\n\n /** Save all inputs in global variable state */\n var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\n\n Array.prototype.map.call(inputs, function (current) {\n\n if (!current.type || current.type == 'text' || current.type == 'textarea') {\n\n editor.state.inputs.push(current);\n\n }\n\n });\n\n };\n\n /**\n * Adds first initial block on empty redactor\n */\n ui.addInitialBlock = function () {\n\n var initialBlockType = editor.settings.initialBlockPlugin,\n initialBlock;\n\n if ( !editor.tools[initialBlockType] ) {\n\n editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\n return;\n\n }\n\n initialBlock = editor.tools[initialBlockType].render();\n\n initialBlock.setAttribute('data-placeholder', 'Расскажите свою историю...');\n\n editor.content.insertBlock({\n type : initialBlockType,\n block : initialBlock\n });\n\n editor.content.workingNodeChanged(initialBlock);\n\n };\n\n ui.setInlineToolbarButtonBehaviour = function (button, type) {\n\n editor.listeners.add(button, 'mousedown', function (event) {\n\n editor.toolbar.inline.toolClicked(event, type);\n\n }, false);\n\n };\n\n return ui;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/ui.js","/**\n *\n * Codex.Editor Transport Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (transport) {\n\n let editor = codex.editor;\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 editor.listeners.add(input, '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\nmodule.exports = (function (renderer) {\n\n let editor = codex.editor;\n\n /**\n * Asyncronously parses input JSON to redactor blocks\n */\n renderer.makeBlocksFromData = function () {\n\n /**\n * If redactor is empty, add first paragraph to start writing\n */\n if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {\n\n editor.ui.addInitialBlock();\n return;\n\n }\n\n Promise.resolve()\n\n /** First, get JSON from state */\n .then(function () {\n\n return editor.state.blocks;\n\n })\n\n /** Then, start to iterate they */\n .then(editor.renderer.appendBlocks)\n\n /** Write log if something goes wrong */\n .catch(function (error) {\n\n editor.core.log('Error while parsing JSON: %o', 'error', error);\n\n });\n\n };\n\n /**\n * Parses JSON to blocks\n * @param {object} data\n * @return Primise -> nodeList\n */\n renderer.appendBlocks = function (data) {\n\n var blocks = data.items;\n\n /**\n * Sequence of one-by-one blocks appending\n * Uses to save blocks order after async-handler\n */\n var nodeSequence = Promise.resolve();\n\n for (var index = 0; index < blocks.length ; index++ ) {\n\n /** Add node to sequence at specified index */\n editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\n\n }\n\n };\n\n /**\n * Append node at specified index\n */\n renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\n\n /** We need to append node to sequence */\n nodeSequence\n\n /** first, get node async-aware */\n .then(function () {\n\n return editor.renderer.getNodeAsync(blocks, index);\n\n })\n\n /**\n * second, compose editor-block from JSON object\n */\n .then(editor.renderer.createBlockFromData)\n\n /**\n * now insert block to redactor\n */\n .then(function (blockData) {\n\n /**\n * blockData has 'block', 'type' and 'stretched' information\n */\n editor.content.insertBlock(blockData);\n\n /** Pass created block to next step */\n return blockData.block;\n\n })\n\n /** Log if something wrong with node */\n .catch(function (error) {\n\n editor.core.log('Node skipped while parsing because %o', 'error', error);\n\n });\n\n };\n\n /**\n * Asynchronously returns block data from blocksList by index\n * @return Promise to node\n */\n renderer.getNodeAsync = function (blocksList, index) {\n\n return Promise.resolve().then(function () {\n\n return {\n tool : blocksList[index],\n position : index\n };\n\n });\n\n };\n\n /**\n * Creates editor block by JSON-data\n *\n * @uses render method of each plugin\n *\n * @param {Object} toolData.tool\n * { header : {\n * text: '',\n * type: 'H3', ...\n * }\n * }\n * @param {Number} toolData.position - index in input-blocks array\n * @return {Object} with type and Element\n */\n renderer.createBlockFromData = function ( toolData ) {\n\n /** New parser */\n var block,\n tool = toolData.tool,\n pluginName = tool.type,\n anchor = tool.anchor,\n cover = tool.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 if ( editor.tools[pluginName].available === false ) {\n\n block = editor.draw.unavailableBlock();\n\n block.innerHTML = editor.tools[pluginName].loadingMessage;\n\n /**\n * Saver will extract data from initial block data by position in array\n */\n block.dataset.inputPosition = toolData.position;\n\n } else {\n\n /** New Parser */\n block = editor.tools[pluginName].render(tool.data);\n\n }\n\n /** is first-level block stretched */\n var stretched = editor.tools[pluginName].isStretched || false;\n\n /** Retrun type and block */\n return {\n type : pluginName,\n block : block,\n stretched : stretched,\n cover : cover,\n anchor : anchor\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\nmodule.exports = (function (saver) {\n\n let editor = codex.editor;\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 anchor = block.dataset.anchor;\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,\n position,\n output,\n coverFlag = false;\n\n /** If plugin wasn't available then return data from cache */\n if ( editor.tools[pluginName].available === false ) {\n\n position = pluginsContent.dataset.inputPosition;\n\n savedData = codex.editor.state.blocks.items[position].data;\n coverFlag = codex.editor.state.blocks.items[position].cover;\n anchor = codex.editor.state.blocks.items[position].anchor;\n\n } else {\n\n savedData = editor.tools[pluginName].save(pluginsContent);\n coverFlag = block.classList.contains(editor.ui.className.BLOCK_IN_FEED_MODE);\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 }\n\n output = {\n type : pluginName,\n anchor : anchor,\n data : savedData\n };\n\n /** Marks Blocks that will be in main page */\n output.cover = coverFlag;\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.12\n */\n\nmodule.exports = (function (content) {\n\n let editor = codex.editor;\n\n /**\n * Links to current active block\n * @type {null | Element}\n */\n content.currentNode = null;\n\n /**\n * clicked in redactor area\n * @type {null | Boolean}\n */\n content.editorAreaHightlighted = null;\n\n /**\n * 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 if (targetBlock.classList.contains(editor.ui.className.BLOCK_WITH_ANCHOR)) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\n }\n\n /**\n * Saving anchor\n */\n newBlock.dataset.anchor = targetBlock.dataset.anchor;\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 anchor = blockData.anchor,\n isStretched = blockData.stretched;\n\n var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);\n\n if (cover === true) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_IN_FEED_MODE);\n\n }\n\n if (anchor) {\n\n newBlock.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\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 tool = tool || editor.content.currentNode.dataset.tool;\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, anchor) {\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 newBlock.dataset.anchor = anchor || '';\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 /**\n * Finds closest Contenteditable parent from Element\n * @param {Element} node element looking from\n * @return {Element} node contenteditable\n */\n content.getEditableParent = function (node) {\n\n while (node && node.contentEditable != 'true') {\n\n node = node.parentNode;\n\n }\n\n return node;\n\n };\n\n return content;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/content.js","/**\n * Codex Editor toolbar module\n *\n * Contains:\n * - Inline toolbox\n * - Toolbox within plus button\n * - Settings section\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (toolbar) {\n\n let editor = codex.editor;\n\n toolbar.settings = require('./settings');\n toolbar.inline = require('./inline');\n toolbar.toolbox = require('./toolbox');\n\n /**\n * Margin between focused node and toolbar\n */\n toolbar.defaultToolbarHeight = 49;\n\n toolbar.defaultOffset = 34;\n\n toolbar.opened = false;\n\n toolbar.current = null;\n\n /**\n * @protected\n */\n toolbar.open = function () {\n\n if (editor.hideToolbar) {\n\n return;\n\n }\n\n 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\nmodule.exports = (function (settings) {\n\n let editor = codex.editor;\n\n settings.opened = false;\n\n settings.setting = null;\n settings.actions = null;\n\n 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 editor.anchors.settingsOpened(editor.content.currentNode);\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 anchorInput;\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 anchorInput = editor.toolbar.settings.makeAnchorInput();\n\n /**\n * Fill defaultSettings\n */\n\n /**\n * Input for anchor for block\n */\n editor.nodes.defaultSettings.appendChild(anchorInput);\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 : 'Вывести в ленте'\n };\n\n } else {\n\n data = {\n innerHTML : 'Не выводить в ленте'\n };\n\n }\n\n setting = editor.draw.node('DIV', editor.ui.className.SETTINGS_ITEM, data);\n editor.listeners.add(setting, '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 settings.makeAnchorInput = function () {\n\n var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),\n hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),\n anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });\n\n editor.listeners.add(anchor, 'keydown', editor.anchors.keyDownOnAnchorInput );\n editor.listeners.add(anchor, 'keyup', editor.anchors.keyUpOnAnchorInput );\n editor.listeners.add(anchor, 'input', editor.anchors.anchorChanged );\n editor.listeners.add(anchor, 'blur', editor.anchors.anchorChanged );\n\n anchorWrapper.appendChild(hash);\n anchorWrapper.appendChild(anchor);\n\n editor.anchors.input = anchor;\n\n return anchorWrapper;\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 : '' }),\n actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\n confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }),\n cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' });\n\n editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\n\n editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\n\n editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\n\n actionWrapper.appendChild(confirmAction);\n actionWrapper.appendChild(cancelAction);\n\n removeBlockWrapper.appendChild(settingButton);\n removeBlockWrapper.appendChild(actionWrapper);\n\n /** Save setting */\n editor.toolbar.settings.setting = settingButton;\n editor.toolbar.settings.actions = actionWrapper;\n\n return removeBlockWrapper;\n\n };\n\n settings.removeButtonClicked = function () {\n\n var action = editor.toolbar.settings.actions;\n\n if (action.classList.contains('opened')) {\n\n editor.toolbar.settings.hideRemoveActions();\n\n } else {\n\n editor.toolbar.settings.showRemoveActions();\n\n }\n\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.close();\n\n };\n\n settings.cancelRemovingRequest = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n settings.confirmRemovingRequest = function () {\n\n var currentBlock = editor.content.currentNode,\n firstLevelBlocksCount;\n\n currentBlock.remove();\n\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\n /**\n * If all blocks are removed\n */\n if (firstLevelBlocksCount === 0) {\n\n /** update currentNode variable */\n editor.content.currentNode = null;\n\n /** Inserting new empty initial block */\n editor.ui.addInitialBlock();\n\n }\n\n editor.ui.saveInputs();\n\n editor.toolbar.close();\n\n };\n\n settings.showRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.add('opened');\n\n };\n\n settings.hideRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n return settings;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/settings.js","/**\n * Inline toolbar\n *\n * Contains from tools:\n * Bold, Italic, Underline and Anchor\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (inline) {\n\n let editor = codex.editor;\n\n inline.buttonsOpened = null;\n inline.actionsOpened = null;\n inline.wrappersOffset = null;\n\n /**\n * saving selection that need for execCommand for styling\n *\n */\n inline.storedSelection = null;\n\n /**\n * @protected\n *\n * Open inline toobar\n */\n inline.show = function () {\n\n var currentNode = editor.content.currentNode,\n tool = currentNode.dataset.tool,\n plugin;\n\n /**\n * tool allowed to open inline toolbar\n */\n plugin = editor.tools[tool];\n\n if (!plugin.showInlineToolbar)\n return;\n\n var selectedText = inline.getSelectionText(),\n toolbar = editor.nodes.inlineToolbar.wrapper;\n\n if (selectedText.length > 0) {\n\n /** Move toolbar and open */\n editor.toolbar.inline.move();\n\n /** Open inline toolbar */\n toolbar.classList.add('opened');\n\n /** show buttons of inline toolbar */\n editor.toolbar.inline.showButtons();\n\n }\n\n };\n\n /**\n * @protected\n *\n * Closes inline toolbar\n */\n inline.close = function () {\n\n var toolbar = editor.nodes.inlineToolbar.wrapper;\n\n toolbar.classList.remove('opened');\n\n };\n\n /**\n * @private\n *\n * Moving toolbar\n */\n inline.move = function () {\n\n if (!this.wrappersOffset) {\n\n this.wrappersOffset = this.getWrappersOffset();\n\n }\n\n var coords = this.getSelectionCoords(),\n defaultOffset = 0,\n toolbar = editor.nodes.inlineToolbar.wrapper,\n newCoordinateX,\n newCoordinateY;\n\n if (toolbar.offsetHeight === 0) {\n\n defaultOffset = 40;\n\n }\n\n newCoordinateX = coords.x - this.wrappersOffset.left;\n newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;\n\n toolbar.style.transform = `translate3D(${Math.floor(newCoordinateX)}px, ${Math.floor(newCoordinateY)}px, 0)`;\n\n /** Close everything */\n editor.toolbar.inline.closeButtons();\n editor.toolbar.inline.closeAction();\n\n };\n\n /**\n * @private\n *\n * Tool Clicked\n */\n\n inline.toolClicked = function (event, type) {\n\n /**\n * For simple tools we use default browser function\n * For more complicated tools, we should write our own behavior\n */\n switch (type) {\n case 'createLink' : editor.toolbar.inline.createLinkAction(event, type); break;\n default : editor.toolbar.inline.defaultToolAction(type); break;\n }\n\n /**\n * highlight buttons\n * after making some action\n */\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\n };\n\n /**\n * @private\n *\n * Saving wrappers offset in DOM\n */\n inline.getWrappersOffset = function () {\n\n var wrapper = editor.nodes.wrapper,\n offset = this.getOffset(wrapper);\n\n this.wrappersOffset = offset;\n return offset;\n\n };\n\n /**\n * @private\n *\n * Calculates offset of DOM element\n *\n * @param el\n * @returns {{top: number, left: number}}\n */\n inline.getOffset = function ( el ) {\n\n var _x = 0;\n var _y = 0;\n\n while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {\n\n _x += (el.offsetLeft + el.clientLeft);\n _y += (el.offsetTop + el.clientTop);\n el = el.offsetParent;\n\n }\n return { top: _y, left: _x };\n\n };\n\n /**\n * @private\n *\n * Calculates position of selected text\n * @returns {{x: number, y: number}}\n */\n inline.getSelectionCoords = function () {\n\n var sel = document.selection, range;\n var x = 0, y = 0;\n\n if (sel) {\n\n if (sel.type != 'Control') {\n\n range = sel.createRange();\n range.collapse(true);\n x = range.boundingLeft;\n y = range.boundingTop;\n\n }\n\n } else if (window.getSelection) {\n\n sel = window.getSelection();\n\n if (sel.rangeCount) {\n\n range = sel.getRangeAt(0).cloneRange();\n if (range.getClientRects) {\n\n range.collapse(true);\n var rect = range.getClientRects()[0];\n\n if (!rect) {\n\n return;\n\n }\n\n x = rect.left;\n y = rect.top;\n\n }\n\n }\n\n }\n return { x: x, y: y };\n\n };\n\n /**\n * @private\n *\n * Returns selected text as String\n * @returns {string}\n */\n inline.getSelectionText = function () {\n\n var selectedText = '';\n\n // all modern browsers and IE9+\n if (window.getSelection) {\n\n selectedText = window.getSelection().toString();\n\n }\n\n return selectedText;\n\n };\n\n /** Opens buttons block */\n inline.showButtons = function () {\n\n var buttons = editor.nodes.inlineToolbar.buttons;\n\n buttons.classList.add('opened');\n\n editor.toolbar.inline.buttonsOpened = true;\n\n /** highlight buttons */\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);\n\n };\n\n /** Makes buttons disappear */\n inline.closeButtons = function () {\n\n var buttons = editor.nodes.inlineToolbar.buttons;\n\n buttons.classList.remove('opened');\n\n editor.toolbar.inline.buttonsOpened = false;\n\n };\n\n /** Open buttons defined action if exist */\n inline.showActions = function () {\n\n var action = editor.nodes.inlineToolbar.actions;\n\n action.classList.add('opened');\n\n editor.toolbar.inline.actionsOpened = true;\n\n };\n\n /** Close actions block */\n inline.closeAction = function () {\n\n var action = editor.nodes.inlineToolbar.actions;\n\n action.innerHTML = '';\n action.classList.remove('opened');\n editor.toolbar.inline.actionsOpened = false;\n\n };\n\n\n /**\n * Callback for keydowns in inline toolbar \"Insert link...\" input\n */\n let inlineToolbarAnchorInputKeydown_ = function (event) {\n\n if (event.keyCode != editor.core.keys.ENTER) {\n\n return;\n\n }\n\n let editable = editor.content.currentNode,\n storedSelection = editor.toolbar.inline.storedSelection;\n\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\n editor.toolbar.inline.setAnchor(this.value);\n\n /**\n * Preventing events that will be able to happen\n */\n event.preventDefault();\n event.stopImmediatePropagation();\n\n editor.toolbar.inline.clearRange();\n\n };\n\n /** Action for link creation or for setting anchor */\n inline.createLinkAction = function (event) {\n\n var isActive = this.isLinkActive();\n\n var editable = editor.content.currentNode,\n storedSelection = editor.toolbar.inline.saveSelection(editable);\n\n /** Save globally selection */\n editor.toolbar.inline.storedSelection = storedSelection;\n\n if (isActive) {\n\n\n /**\n * Changing stored selection. if we want to remove anchor from word\n * we should remove anchor from whole word, not only selected part.\n * The solution is than we get the length of current link\n * Change start position to - end of selection minus length of anchor\n */\n editor.toolbar.inline.restoreSelection(editable, storedSelection);\n\n editor.toolbar.inline.defaultToolAction('unlink');\n\n } else {\n\n /** Create input and close buttons */\n var action = editor.draw.inputForLink();\n\n editor.nodes.inlineToolbar.actions.appendChild(action);\n\n editor.toolbar.inline.closeButtons();\n editor.toolbar.inline.showActions();\n\n /**\n * focus to input\n * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus\n * Prevents event after showing input and when we need to focus an input which is in unexisted form\n */\n action.focus();\n event.preventDefault();\n\n /** Callback to link action */\n editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);\n\n }\n\n };\n\n inline.isLinkActive = function () {\n\n var isActive = false;\n\n editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {\n\n var dataType = tool.dataset.type;\n\n if (dataType == 'link' && tool.classList.contains('hightlighted')) {\n\n isActive = true;\n\n }\n\n });\n\n return isActive;\n\n };\n\n /** default action behavior of tool */\n inline.defaultToolAction = function (type) {\n\n document.execCommand(type, false, null);\n\n };\n\n /**\n * @private\n *\n * Sets URL\n *\n * @param {String} url - URL\n */\n inline.setAnchor = function (url) {\n\n document.execCommand('createLink', false, url);\n\n /** Close after URL inserting */\n editor.toolbar.inline.closeAction();\n\n };\n\n /**\n * @private\n *\n * Saves selection\n */\n inline.saveSelection = function (containerEl) {\n\n var range = window.getSelection().getRangeAt(0),\n preSelectionRange = range.cloneRange(),\n start;\n\n preSelectionRange.selectNodeContents(containerEl);\n preSelectionRange.setEnd(range.startContainer, range.startOffset);\n\n start = preSelectionRange.toString().length;\n\n return {\n start: start,\n end: start + range.toString().length\n };\n\n };\n\n /**\n * @private\n *\n * Sets to previous selection (Range)\n *\n * @param {Element} containerEl - editable element where we restore range\n * @param {Object} savedSel - range basic information to restore\n */\n inline.restoreSelection = function (containerEl, savedSel) {\n\n var range = document.createRange(),\n charIndex = 0;\n\n range.setStart(containerEl, 0);\n range.collapse(true);\n\n var nodeStack = [ containerEl ],\n node,\n foundStart = false,\n stop = false,\n nextCharIndex;\n\n while (!stop && (node = nodeStack.pop())) {\n\n if (node.nodeType == 3) {\n\n nextCharIndex = charIndex + node.length;\n\n if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {\n\n range.setStart(node, savedSel.start - charIndex);\n foundStart = true;\n\n }\n if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {\n\n range.setEnd(node, savedSel.end - charIndex);\n stop = true;\n\n }\n charIndex = nextCharIndex;\n\n } else {\n\n var i = node.childNodes.length;\n\n while (i--) {\n\n nodeStack.push(node.childNodes[i]);\n\n }\n\n }\n\n }\n\n var sel = window.getSelection();\n\n sel.removeAllRanges();\n sel.addRange(range);\n\n };\n\n /**\n * @private\n *\n * Removes all ranges from window selection\n */\n inline.clearRange = function () {\n\n var selection = window.getSelection();\n\n selection.removeAllRanges();\n\n };\n\n /**\n * @private\n *\n * sets or removes hightlight\n */\n inline.hightlight = function (tool) {\n\n var dataType = tool.dataset.type;\n\n if (document.queryCommandState(dataType)) {\n\n editor.toolbar.inline.setButtonHighlighted(tool);\n\n } else {\n\n editor.toolbar.inline.removeButtonsHighLight(tool);\n\n }\n\n /**\n *\n * hightlight for anchors\n */\n var selection = window.getSelection(),\n tag = selection.anchorNode.parentNode;\n\n if (tag.tagName == 'A' && dataType == 'link') {\n\n editor.toolbar.inline.setButtonHighlighted(tool);\n\n }\n\n };\n\n /**\n * @private\n *\n * Mark button if text is already executed\n */\n inline.setButtonHighlighted = function (button) {\n\n button.classList.add('hightlighted');\n\n /** At link tool we also change icon */\n if (button.dataset.type == 'link') {\n\n var icon = button.childNodes[0];\n\n icon.classList.remove('ce-icon-link');\n icon.classList.add('ce-icon-unlink');\n\n }\n\n };\n\n /**\n * @private\n *\n * Removes hightlight\n */\n inline.removeButtonsHighLight = function (button) {\n\n button.classList.remove('hightlighted');\n\n /** At link tool we also change icon */\n if (button.dataset.type == 'link') {\n\n var icon = button.childNodes[0];\n\n icon.classList.remove('ce-icon-unlink');\n icon.classList.add('ce-icon-link');\n\n }\n\n };\n\n\n return inline;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/inline.js","/**\n * Codex Editor toolbox\n *\n * All tools be able to appended here\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (toolbox) {\n\n let editor = codex.editor;\n\n toolbox.opened = false;\n\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 editor.toolbar.current = null;\n\n };\n\n toolbox.leaf = function () {\n\n let currentTool = editor.toolbar.current,\n tools = Object.keys(editor.tools),\n barButtons = editor.nodes.toolbarButtons,\n nextToolIndex = 0,\n toolToSelect,\n visibleTool,\n tool;\n\n if ( !currentTool ) {\n\n /** Get first tool from object*/\n for(tool in editor.tools) {\n\n if (editor.tools[tool].displayInToolbox) {\n\n break;\n\n }\n\n nextToolIndex ++;\n\n }\n\n } else {\n\n nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;\n visibleTool = tools[nextToolIndex];\n\n while (!editor.tools[visibleTool].displayInToolbox) {\n\n nextToolIndex = (nextToolIndex + 1) % tools.length;\n visibleTool = tools[nextToolIndex];\n\n }\n\n }\n\n toolToSelect = tools[nextToolIndex];\n\n for ( var button in barButtons ) {\n\n barButtons[button].classList.remove('selected');\n\n }\n\n barButtons[toolToSelect].classList.add('selected');\n editor.toolbar.current = toolToSelect;\n\n };\n\n /**\n * Transforming selected node type into selected toolbar element type\n * @param {event} event\n */\n toolbox.toolClicked = function (event) {\n\n /**\n * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty\n */\n var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],\n tool = editor.tools[editor.toolbar.current],\n workingNode = editor.content.currentNode,\n currentInputIndex = editor.caret.inputIndex,\n newBlockContent,\n appendCallback,\n blockData;\n\n /** Make block from plugin */\n newBlockContent = tool.render();\n\n /** information about block */\n blockData = {\n block : newBlockContent,\n type : tool.type,\n stretched : false\n };\n\n if (\n workingNode &&\n UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 &&\n workingNode.textContent.trim() === ''\n ) {\n\n /** Replace current block */\n editor.content.switchBlock(workingNode, newBlockContent, tool.type);\n\n } else {\n\n /** Insert new Block from plugin */\n editor.content.insertBlock(blockData);\n\n /** increase input index */\n currentInputIndex++;\n\n }\n\n /** Fire tool append callback */\n appendCallback = tool.appendCallback;\n\n if (appendCallback && typeof appendCallback == 'function') {\n\n appendCallback.call(event);\n\n }\n\n window.setTimeout(function () {\n\n /** Set caret to current block */\n editor.caret.setToBlock(currentInputIndex);\n\n }, 10);\n\n\n /**\n * Changing current Node\n */\n editor.content.workingNodeChanged();\n\n /**\n * Move toolbar when node is changed\n */\n editor.toolbar.move();\n\n };\n\n return toolbox;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/toolbox.js","/**\n * Codex Editor callbacks module\n *\n * @author Codex Team\n * @version 1.3.10\n */\n\nmodule.exports = (function (callbacks) {\n\n let editor = codex.editor;\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\n var inputs = editor.content.currentNode.querySelectorAll('textarea, input'),\n inputsAreEmpty = true,\n textContentIsEmpty = !editor.content.currentNode.textContent.trim();\n\n Array.prototype.map.call(inputs, function (input) {\n\n if (input.type == 'textarea' || input.type == 'text') {\n\n inputsAreEmpty = inputsAreEmpty && !input.value.trim();\n\n }\n\n });\n\n\n var blockIsEmpty = textContentIsEmpty && inputsAreEmpty;\n\n if (!blockIsEmpty) {\n\n return;\n\n }\n\n if ( !editor.toolbar.opened ) {\n\n editor.toolbar.open();\n\n }\n\n if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\n editor.toolbar.toolbox.open();\n\n } else {\n\n editor.toolbar.toolbox.leaf();\n\n }\n\n 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

    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 if (!inputIsEmpty) {\n\n /** Mark current block */\n editor.content.markBlock();\n\n }\n\n if ( isInitialType && inputIsEmpty ) {\n\n /** Show plus button */\n editor.toolbar.showPlusButton();\n\n }\n\n\n };\n\n /**\n * This method allows to define, is caret in contenteditable element or not.\n * 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 (isNativeInput(event.target)) {\n\n /** If input value is empty - remove block */\n if (event.target.value.trim() == '') {\n\n block.remove();\n\n } else {\n\n return;\n\n }\n\n }\n\n if (block.textContent.trim()) {\n\n range = editor.content.getRange();\n selectionLength = range.endOffset - range.startOffset;\n\n if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {\n\n editor.content.mergeBlocks(currentInputIndex);\n\n } else {\n\n return;\n\n }\n\n }\n\n if (!selectionLength) {\n\n block.remove();\n\n }\n\n\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\n /**\n * If all blocks are removed\n */\n if (firstLevelBlocksCount === 0) {\n\n /** update currentNode variable */\n editor.content.currentNode = null;\n\n /** Inserting new empty initial block */\n editor.ui.addInitialBlock();\n\n /** Updating inputs state after deleting last block */\n editor.ui.saveInputs();\n\n /** Set to current appended block */\n window.setTimeout(function () {\n\n editor.caret.setToPreviousBlock(1);\n\n }, 10);\n\n } else {\n\n if (editor.caret.inputIndex !== 0) {\n\n /** Target block is not first */\n editor.caret.setToPreviousBlock(editor.caret.inputIndex);\n\n } else {\n\n /** If we try to delete first block */\n editor.caret.setToNextBlock(editor.caret.inputIndex);\n\n }\n\n }\n\n editor.toolbar.move();\n\n if (!editor.toolbar.opened) {\n\n editor.toolbar.open();\n\n }\n\n /** Updating inputs state */\n editor.ui.saveInputs();\n\n /** Prevent default browser behaviour */\n event.preventDefault();\n\n };\n\n /**\n * 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 /** If area is input or textarea then allow default behaviour */\n if ( isNativeInput(event.target) ) {\n\n return;\n\n }\n\n /** Prevent default behaviour */\n event.preventDefault();\n\n var editableParent = editor.content.getEditableParent(event.target),\n currentNode = editor.content.currentNode;\n\n /** Allow paste when event target placed in Editable element */\n if (!editableParent) {\n\n return;\n\n }\n\n /** get html pasted data - dirty data */\n var htmlData = event.clipboardData.getData('text/html'),\n plainData = event.clipboardData.getData('text/plain');\n\n /** Temporary DIV that is used to work with 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 if ( htmlData.trim() != '' ) {\n\n cleanData = cleaner.clean(htmlData);\n div.innerHTML = cleanData;\n\n } else {\n\n div.innerText = plainData.toString();\n\n }\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 if (editor.tools[currentNode.dataset.tool].allowRenderOnPaste) {\n\n if (editor.paste.pasted(event)) return;\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 /**\n * Check block for\n * @param target\n */\n var isNativeInput = function (target) {\n\n var nativeInputAreas = ['INPUT', 'TEXTAREA'];\n\n return (nativeInputAreas.indexOf(target.tagName) != -1);\n\n };\n\n return callbacks;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/callbacks.js","/**\n * Codex Editor Draw module\n *\n * @author Codex Team\n * @version 1.0.\n */\n\nmodule.exports = (function (draw) {\n\n /**\n * Base editor wrapper\n */\n draw.wrapper = function () {\n\n var wrapper = document.createElement('div');\n\n wrapper.className += 'codex-editor';\n\n return wrapper;\n\n };\n\n /**\n * Content-editable holder\n */\n draw.redactor = function () {\n\n var redactor = document.createElement('div');\n\n redactor.className += 'ce-redactor';\n\n return redactor;\n\n };\n\n draw.ceBlock = function () {\n\n var block = document.createElement('DIV');\n\n block.className += 'ce_block';\n\n return block;\n\n };\n\n /**\n * Empty toolbar with toggler\n */\n draw.toolbar = function () {\n\n var bar = document.createElement('div');\n\n bar.className += 'ce-toolbar';\n\n return bar;\n\n };\n\n draw.toolbarContent = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.classList.add('ce-toolbar__content');\n\n return wrapper;\n\n };\n\n /**\n * Inline toolbar\n */\n draw.inlineToolbar = function () {\n\n var bar = document.createElement('DIV');\n\n bar.className += 'ce-toolbar-inline';\n\n return bar;\n\n };\n\n /**\n * Wrapper for inline toobar buttons\n */\n draw.inlineToolbarButtons = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.className += 'ce-toolbar-inline__buttons';\n\n return wrapper;\n\n };\n\n /**\n * For some actions\n */\n draw.inlineToolbarActions = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.className += 'ce-toolbar-inline__actions';\n\n return wrapper;\n\n };\n\n draw.inputForLink = function () {\n\n var input = document.createElement('INPUT');\n\n input.type = 'input';\n input.className += 'inputForLink';\n input.placeholder = 'Вставьте ссылку ...';\n input.setAttribute('form', 'defaultForm');\n\n input.setAttribute('autofocus', 'autofocus');\n\n return input;\n\n };\n\n /**\n * @todo Desc\n */\n draw.blockButtons = function () {\n\n var block = document.createElement('div');\n\n block.className += 'ce-toolbar__actions';\n\n return block;\n\n };\n\n /**\n * Block settings panel\n */\n draw.blockSettings = function () {\n\n var settings = document.createElement('div');\n\n settings.className += 'ce-settings';\n\n return settings;\n\n };\n\n draw.defaultSettings = function () {\n\n var div = document.createElement('div');\n\n div.classList.add('ce-settings_default');\n\n return div;\n\n };\n\n draw.pluginsSettings = function () {\n\n var div = document.createElement('div');\n\n div.classList.add('ce-settings_plugin');\n\n return div;\n\n };\n\n draw.plusButton = function () {\n\n var button = document.createElement('span');\n\n button.className = 'ce-toolbar__plus';\n // button.innerHTML = '';\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 = '';\n\n return toggler;\n\n };\n\n /**\n * Redactor tools wrapper\n */\n\n draw.toolbox = function () {\n\n var wrapper = document.createElement('div');\n\n wrapper.className = 'ce-toolbar__tools';\n\n return wrapper;\n\n };\n\n /**\n * @protected\n *\n * Draws tool buttons for toolbox\n *\n * @param {String} type\n * @param {String} classname\n * @returns {Element}\n */\n draw.toolbarButton = function (type, classname) {\n\n var button = document.createElement('li'),\n toolIcon = document.createElement('i'),\n toolTitle = document.createElement('span');\n\n button.dataset.type = type;\n button.setAttribute('title', type);\n\n toolIcon.classList.add(classname);\n toolTitle.classList.add('ce_toolbar_tools--title');\n\n\n button.appendChild(toolIcon);\n button.appendChild(toolTitle);\n\n return button;\n\n };\n\n /**\n * @protected\n *\n * Draws tools for inline toolbar\n *\n * @param {String} type\n * @param {String} classname\n */\n draw.toolbarButtonInline = function (type, classname) {\n\n var button = document.createElement('BUTTON'),\n toolIcon = document.createElement('I');\n\n button.type = 'button';\n button.dataset.type = type;\n toolIcon.classList.add(classname);\n\n button.appendChild(toolIcon);\n\n return button;\n\n };\n\n /**\n * Redactor block\n */\n draw.block = function (tagName, content) {\n\n var node = document.createElement(tagName);\n\n node.innerHTML = content || '';\n\n return node;\n\n };\n\n /**\n * Creates Node with passed tagName and className\n * @param {string} tagName\n * @param {string} className\n * @param {object} properties - allow to assign properties\n */\n draw.node = function ( tagName, className, properties ) {\n\n var el = document.createElement( tagName );\n\n if ( className ) el.className = className;\n\n if ( properties ) {\n\n for (var name in properties) {\n\n el[name] = properties[name];\n\n }\n\n }\n\n return el;\n\n };\n\n /**\n * Unavailable plugin block\n */\n draw.unavailableBlock = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.classList.add('cdx-unavailable-block');\n\n return wrapper;\n\n };\n\n return draw;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/draw.js","/**\n * Codex Editor Caret Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (caret) {\n\n let editor = codex.editor;\n\n /**\n * @var {int} InputIndex - editable element in DOM\n */\n caret.inputIndex = null;\n\n /**\n * @var {int} offset - caret position in a text node.\n */\n caret.offset = null;\n\n /**\n * @var {int} focusedNodeIndex - we get index of child node from first-level block\n */\n caret.focusedNodeIndex = null;\n\n /**\n * Creates Document Range and sets caret to the element.\n * @protected\n * @uses caret.save — if you need to save caret position\n * @param {Element} el - Changed Node.\n */\n caret.set = function ( el, index, offset) {\n\n offset = offset || caret.offset || 0;\n index = index || caret.focusedNodeIndex || 0;\n\n var childs = el.childNodes,\n nodeToSet;\n\n if ( childs.length === 0 ) {\n\n nodeToSet = el;\n\n } else {\n\n nodeToSet = childs[index];\n\n }\n\n /** If Element is INPUT */\n if (el.contentEditable != 'true') {\n\n el.focus();\n return;\n\n }\n\n if (editor.core.isDomNode(nodeToSet)) {\n\n nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length);\n\n }\n\n var range = document.createRange(),\n selection = window.getSelection();\n\n window.setTimeout(function () {\n\n range.setStart(nodeToSet, offset);\n range.setEnd(nodeToSet, offset);\n\n selection.removeAllRanges();\n selection.addRange(range);\n\n editor.caret.saveCurrentInputIndex();\n\n }, 20);\n\n };\n\n /**\n * @protected\n * Updates index of input and saves it in caret object\n */\n caret.saveCurrentInputIndex = function () {\n\n /** Index of Input that we paste sanitized content */\n var selection = window.getSelection(),\n inputs = editor.state.inputs,\n focusedNode = selection.anchorNode,\n focusedNodeHolder;\n\n if (!focusedNode) {\n\n return;\n\n }\n\n /** Looking for parent contentEditable block */\n while (focusedNode.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 */\n\nmodule.exports = (function (notifications) {\n\n let editor = codex.editor;\n\n var queue = [];\n\n var addToQueue = function (settings) {\n\n queue.push(settings);\n\n var index = 0;\n\n while ( index < queue.length && queue.length > 5) {\n\n if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n\n index++;\n continue;\n\n }\n\n queue[index].close();\n queue.splice(index, 1);\n\n }\n\n };\n\n notifications.createHolder = function () {\n\n var holder = editor.draw.node('DIV', 'cdx-notifications-block');\n\n editor.nodes.notifications = document.body.appendChild(holder);\n\n return holder;\n\n };\n\n\n /**\n * Error notificator. Shows block with message\n * @protected\n */\n notifications.errorThrown = function (errorMsg, event) {\n\n editor.notifications.notification({message: 'This action is not available currently', type: event.type});\n\n };\n\n /**\n *\n * Appends notification\n *\n * settings = {\n * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\n * message - notification message\n * okMsg - confirm button text (default - 'Ok')\n * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\n * confirm - function-handler for ok button click\n * cancel - function-handler for cancel button click. Only for confirm and prompt types\n * time - time (in seconds) after which notification will close (default - 10s)\n * }\n *\n * @param settings\n */\n notifications.notification = function (constructorSettings) {\n\n /** Private vars and methods */\n var notification = null,\n cancel = null,\n type = null,\n confirm = null,\n inputField = null;\n\n var confirmHandler = function () {\n\n close();\n\n if (typeof confirm !== 'function' ) {\n\n return;\n\n }\n\n if (type == 'prompt') {\n\n confirm(inputField.value);\n return;\n\n }\n\n confirm();\n\n };\n\n var cancelHandler = function () {\n\n close();\n\n if (typeof cancel !== 'function' ) {\n\n return;\n\n }\n\n cancel();\n\n };\n\n\n /** Public methods */\n function create(settings) {\n\n if (!(settings && settings.message)) {\n\n editor.core.log('Can\\'t create notification. Message is missed');\n return;\n\n }\n\n settings.type = settings.type || 'alert';\n settings.time = settings.time*1000 || 10000;\n\n var wrapper = editor.draw.node('DIV', 'cdx-notification'),\n message = editor.draw.node('DIV', 'cdx-notification__message'),\n input = editor.draw.node('INPUT', 'cdx-notification__input'),\n okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\n cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\n\n message.textContent = settings.message;\n okBtn.textContent = settings.okMsg || 'ОК';\n cancelBtn.textContent = settings.cancelMsg || 'Отмена';\n\n editor.listeners.add(okBtn, 'click', confirmHandler);\n editor.listeners.add(cancelBtn, 'click', cancelHandler);\n\n wrapper.appendChild(message);\n\n if (settings.type == 'prompt') {\n\n wrapper.appendChild(input);\n\n }\n\n wrapper.appendChild(okBtn);\n\n if (settings.type == 'prompt' || settings.type == 'confirm') {\n\n wrapper.appendChild(cancelBtn);\n\n }\n\n wrapper.classList.add('cdx-notification-' + settings.type);\n wrapper.dataset.type = settings.type;\n\n notification = wrapper;\n type = settings.type;\n confirm = settings.confirm;\n cancel = settings.cancel;\n inputField = input;\n\n if (settings.type != 'prompt' && settings.type != 'confirm') {\n\n window.setTimeout(close, settings.time);\n\n }\n\n };\n\n function send() {\n\n editor.nodes.notifications.appendChild(notification);\n inputField.focus();\n\n editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\n\n window.setTimeout(function () {\n\n editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n\n }, 100);\n\n addToQueue({type: type, close: close});\n\n };\n\n function close() {\n\n notification.remove();\n\n };\n\n\n if (constructorSettings) {\n\n create(constructorSettings);\n send();\n\n }\n\n return {\n create: create,\n send: send,\n close: close\n };\n\n };\n\n notifications.clear = function () {\n\n editor.nodes.notifications.innerHTML = '';\n queue = [];\n\n };\n\n return notifications;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/notifications.js","/**\n * Codex Editor Parser Module\n *\n * @author Codex Team\n * @version 1.1\n */\n\nmodule.exports = (function (parser) {\n\n let editor = codex.editor;\n\n /** inserting text */\n parser.insertPastedContent = function (blockType, tag) {\n\n editor.content.insertBlock({\n type : blockType.type,\n block : blockType.render({\n text : tag.innerHTML\n })\n });\n\n };\n\n /**\n * Check DOM node for display style: separated block or child-view\n */\n parser.isFirstLevelBlock = function (node) {\n\n return node.nodeType == editor.core.nodeTypes.TAG &&\n node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n\n };\n\n return parser;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/parser.js","/**\n * Codex Sanitizer\n */\n\nmodule.exports = (function (sanitizer) {\n\n var janitor = require('html-janitor');\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.

  • ...); if\n // they are, we want to unwrap the inner block element.\n var isNotTopContainer = !! parentNode.parentNode;\n var isNestedBlockElement =\n isBlockElement(parentNode) &&\n isBlockElement(node) &&\n isNotTopContainer;\n\n var nodeName = node.nodeName.toLowerCase();\n\n var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\n var isInvalid = isInline && containsBlockElement;\n\n // Drop tag entirely according to the whitelist *and* if the markup\n // is invalid.\n if (isInvalid || shouldRejectNode(node, allowedAttrs)\n || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n // Do not keep the inner text of SCRIPT/STYLE elements.\n if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n while (node.childNodes.length > 0) {\n parentNode.insertBefore(node.childNodes[0], node);\n }\n }\n parentNode.removeChild(node);\n\n this._sanitize(parentNode);\n break;\n }\n\n // Sanitize attributes\n for (var a = 0; a < node.attributes.length; a += 1) {\n var attr = node.attributes[a];\n\n if (shouldRejectAttr(attr, allowedAttrs, node)) {\n node.removeAttribute(attr.name);\n // Shift the array to continue looping.\n a = a - 1;\n }\n }\n\n // Sanitize children\n this._sanitize(node);\n\n // Mark node as sanitized so it's ignored in future runs\n node._sanitized = true;\n } while ((node = treeWalker.nextSibling()));\n };\n\n function createTreeWalker(node) {\n return document.createTreeWalker(node,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n null, false);\n }\n\n function getAllowedAttrs(config, nodeName, node){\n if (typeof config.tags[nodeName] === 'function') {\n return config.tags[nodeName](node);\n } else {\n return config.tags[nodeName];\n }\n }\n\n function shouldRejectNode(node, allowedAttrs){\n if (typeof allowedAttrs === 'undefined') {\n return true;\n } else if (typeof allowedAttrs === 'boolean') {\n return !allowedAttrs;\n }\n\n return false;\n }\n\n function shouldRejectAttr(attr, allowedAttrs, node){\n var attrName = attr.name.toLowerCase();\n\n if (allowedAttrs === true){\n return false;\n } else if (typeof allowedAttrs[attrName] === 'function'){\n return !allowedAttrs[attrName](attr.value, node);\n } else if (typeof allowedAttrs[attrName] === 'undefined'){\n return true;\n } else if (allowedAttrs[attrName] === false) {\n return true;\n } else if (typeof allowedAttrs[attrName] === 'string') {\n return (allowedAttrs[attrName] !== attr.value);\n }\n\n return false;\n }\n\n return HTMLJanitor;\n\n}));\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/html-janitor/src/html-janitor.js\n// module id = 18\n// module chunks = 0","/**\n * Codex Editor Anchors module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = function (anchors) {\n\n let editor = codex.editor;\n\n anchors.input = null;\n anchors.currentNode = null;\n\n anchors.settingsOpened = function (currentBlock) {\n\n anchors.currentNode = currentBlock;\n anchors.input.value = anchors.currentNode.dataset.anchor || '';\n\n };\n\n anchors.anchorChanged = function (e) {\n\n var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);\n\n anchors.currentNode.dataset.anchor = newAnchor;\n\n if (newAnchor.trim() !== '') {\n\n anchors.currentNode.classList.add(editor.ui.className.BLOCK_WITH_ANCHOR);\n\n } else {\n\n anchors.currentNode.classList.remove(editor.ui.className.BLOCK_WITH_ANCHOR);\n\n }\n\n };\n\n anchors.keyDownOnAnchorInput = function (e) {\n\n if (e.keyCode == editor.core.keys.ENTER) {\n\n e.preventDefault();\n e.stopPropagation();\n\n e.target.blur();\n editor.toolbar.settings.close();\n\n }\n\n };\n\n anchors.keyUpOnAnchorInput = function (e) {\n\n if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {\n\n e.stopPropagation();\n\n }\n\n };\n\n anchors.rusToTranslit = function (string) {\n\n var ru = [\n 'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й',\n 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф',\n 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'\n ],\n en = [\n 'A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y',\n 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F',\n 'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya'\n ];\n\n for (var i = 0; i < ru.length; i++) {\n\n string = string.split(ru[i]).join(en[i]);\n string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());\n\n }\n\n string = string.replace(/[^0-9a-zA-Z_]+/g, '-');\n\n return string;\n\n };\n\n return anchors;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/anchors.js","/**\n * Codex Editor Listeners module\n *\n * @author Codex Team\n * @version 1.0\n */\n\n/**\n * Module-decorator for event listeners assignment\n */\nmodule.exports = function (listeners) {\n\n var allListeners = [];\n\n /**\n * Search methods\n *\n * byElement, byType and byHandler returns array of suitable listeners\n * one and all takes element, eventType, and handler and returns first (all) suitable listener\n *\n */\n listeners.search = function () {\n\n var byElement = function (element, context) {\n\n var listenersOnElement = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.element === element) {\n\n listenersOnElement.push(listener);\n\n }\n\n }\n\n return listenersOnElement;\n\n };\n\n var byType = function (eventType, context) {\n\n var listenersWithType = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.type === eventType) {\n\n listenersWithType.push(listener);\n\n }\n\n }\n\n return listenersWithType;\n\n };\n\n var byHandler = function (handler, context) {\n\n var listenersWithHandler = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.handler === handler) {\n\n listenersWithHandler.push(listener);\n\n }\n\n }\n\n return listenersWithHandler;\n\n };\n\n var one = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result[0];\n\n };\n\n var all = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result;\n\n };\n\n return {\n byElement : byElement,\n byType : byType,\n byHandler : byHandler,\n one : one,\n all : all\n };\n\n }();\n\n listeners.add = function (element, eventType, handler, isCapture) {\n\n element.addEventListener(eventType, handler, isCapture);\n\n var data = {\n element: element,\n type: eventType,\n handler: handler\n };\n\n var alreadyAddedListener = listeners.search.one(element, eventType, handler);\n\n if (!alreadyAddedListener) {\n\n allListeners.push(data);\n\n }\n\n };\n\n listeners.remove = function (element, eventType, handler) {\n\n element.removeEventListener(eventType, handler);\n\n var existingListeners = listeners.search.all(element, eventType, handler);\n\n for (var i = 0; i < existingListeners.length; i++) {\n\n var index = allListeners.indexOf(existingListeners[i]);\n\n if (index > 0) {\n\n allListeners.splice(index, 1);\n\n }\n\n }\n\n };\n\n listeners.removeAll = function () {\n\n allListeners.map(function (current) {\n\n listeners.remove(current.element, current.type, current.handler);\n\n });\n\n };\n\n listeners.get = function (element, eventType, handler) {\n\n return listeners.search.all(element, eventType, handler);\n\n };\n\n return listeners;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/listeners.js","/**\n * Codex Editor Destroyer module\n *\n * @auhor Codex Team\n * @version 1.0\n */\n\nmodule.exports = function (destroyer) {\n\n let editor = codex.editor;\n\n destroyer.removeNodes = function () {\n\n editor.nodes.wrapper.remove();\n editor.nodes.notifications.remove();\n\n };\n\n destroyer.destroyPlugins = function () {\n\n for (var tool in editor.tools) {\n\n if (typeof editor.tools[tool].destroy === 'function') {\n\n editor.tools[tool].destroy();\n\n }\n\n }\n\n };\n\n destroyer.destroyScripts = function () {\n\n var scripts = document.getElementsByTagName('SCRIPT');\n\n for (var i = 0; i < scripts.length; i++) {\n\n if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n\n scripts[i].remove();\n i--;\n\n }\n\n }\n\n };\n\n\n /**\n * Delete editor data from webpage.\n * You should send settings argument with boolean flags:\n * @param settings.ui- remove redactor event listeners and DOM nodes\n * @param settings.scripts - remove redactor scripts from DOM\n * @param settings.plugins - remove plugin's objects\n * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\n * }\n *\n */\n destroyer.destroy = function (settings) {\n\n if (!settings || typeof settings !== 'object') {\n\n return;\n\n }\n\n if (settings.ui) {\n\n destroyer.removeNodes();\n editor.listeners.removeAll();\n\n }\n\n if (settings.scripts) {\n\n destroyer.destroyScripts();\n\n }\n\n if (settings.plugins) {\n\n destroyer.destroyPlugins();\n\n }\n\n if (settings.ui && settings.scripts && settings.core) {\n\n delete codex.editor;\n\n }\n\n };\n\n return destroyer;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/destroyer.js","/**\n * Codex Editor Paste module\n *\n * @author Codex Team\n * @version 1.1.1\n */\n\nmodule.exports = function (paste) {\n\n let editor = codex.editor;\n\n var patterns = [];\n\n paste.prepare = function () {\n\n var tools = editor.tools;\n\n for (var tool in tools) {\n\n if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n\n continue;\n\n }\n\n tools[tool].renderOnPastePatterns.map(function (pattern) {\n\n\n patterns.push(pattern);\n\n });\n\n }\n\n return Promise.resolve();\n\n };\n\n /**\n * Saves data\n * @param event\n */\n paste.pasted = function (event) {\n\n var clipBoardData = event.clipboardData || window.clipboardData,\n content = clipBoardData.getData('Text');\n\n var result = analize(content);\n\n if (result) {\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n }\n\n return result;\n\n };\n\n /**\n * Analizes pated string and calls necessary method\n */\n\n var analize = function (string) {\n\n var result = false,\n content = editor.content.currentNode,\n plugin = content.dataset.tool;\n\n patterns.map( function (pattern) {\n\n var execArray = pattern.regex.exec(string),\n match = execArray && execArray[0];\n\n if ( match && match === string.trim()) {\n\n /** current block is not empty */\n if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {\n\n pasteToNewBlock_();\n\n }\n\n pattern.callback(string, pattern);\n result = true;\n\n }\n\n });\n\n return result;\n\n };\n\n var pasteToNewBlock_ = function () {\n\n /** Create new initial block */\n editor.content.insertBlock({\n\n type : editor.settings.initialBlockPlugin,\n block : editor.tools[editor.settings.initialBlockPlugin].render({\n text : ''\n })\n\n }, false);\n\n };\n\n return paste;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/paste.js"],"sourceRoot":""} \ No newline at end of file diff --git a/example.html b/example.html index 93a3cb69..3e3e7c8d 100644 --- a/example.html +++ b/example.html @@ -51,6 +51,9 @@ + + + - diff --git a/modules/callbacks.js b/modules/callbacks.js index 99fd2984..0c5810f9 100644 --- a/modules/callbacks.js +++ b/modules/callbacks.js @@ -2,7 +2,7 @@ * Codex Editor callbacks module * * @author Codex Team - * @version 1.3.7 + * @version 1.3.10 */ module.exports = (function (callbacks) { @@ -41,7 +41,23 @@ module.exports = (function (callbacks) { callbacks.tabKeyPressed = function (event) { - var blockIsEmpty = !editor.content.currentNode.textContent.trim(); + + var inputs = editor.content.currentNode.querySelectorAll('textarea, input'), + inputsAreEmpty = true, + textContentIsEmpty = !editor.content.currentNode.textContent.trim(); + + Array.prototype.map.call(inputs, function (input) { + + if (input.type == 'textarea' || input.type == 'text') { + + inputsAreEmpty = inputsAreEmpty && !input.value.trim(); + + } + + }); + + + var blockIsEmpty = textContentIsEmpty && inputsAreEmpty; if (!blockIsEmpty) { @@ -691,6 +707,21 @@ module.exports = (function (callbacks) { selectionLength, firstLevelBlocksCount; + if (isNativeInput(event.target)) { + + /** If input value is empty - remove block */ + if (event.target.value.trim() == '') { + + block.remove(); + + } else { + + return; + + } + + } + if (block.textContent.trim()) { range = editor.content.getRange(); @@ -818,11 +849,18 @@ module.exports = (function (callbacks) { */ callbacks.blockPasteCallback = function (event) { + /** If area is input or textarea then allow default behaviour */ + if ( isNativeInput(event.target) ) { + + return; + + } + /** Prevent default behaviour */ event.preventDefault(); var editableParent = editor.content.getEditableParent(event.target), - firstLevelBlock = editor.content.getFirstLevelBlock(event.target); + currentNode = editor.content.currentNode; /** Allow paste when event target placed in Editable element */ if (!editableParent) { @@ -832,7 +870,8 @@ module.exports = (function (callbacks) { } /** get html pasted data - dirty data */ - var data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain'); + var htmlData = event.clipboardData.getData('text/html'), + plainData = event.clipboardData.getData('text/plain'); /** Temporary DIV that is used to work with childs as arrays item */ var div = editor.draw.node('DIV', '', {}), @@ -843,9 +882,16 @@ module.exports = (function (callbacks) { /** Create fragment, that we paste to range after proccesing */ fragment = document.createDocumentFragment(); - cleanData = cleaner.clean(data); + if ( htmlData.trim() != '' ) { - div.innerHTML = cleanData; + cleanData = cleaner.clean(htmlData); + div.innerHTML = cleanData; + + } else { + + div.innerText = plainData.toString(); + + } var node, lastNode; @@ -859,7 +905,7 @@ module.exports = (function (callbacks) { } - if (editor.tools[firstLevelBlock.dataset.tool].allowRenderOnPaste) { + if (editor.tools[currentNode.dataset.tool].allowRenderOnPaste) { if (editor.paste.pasted(event)) return; @@ -933,6 +979,18 @@ module.exports = (function (callbacks) { }; + /** + * Check block for + * @param target + */ + var isNativeInput = function (target) { + + var nativeInputAreas = ['INPUT', 'TEXTAREA']; + + return (nativeInputAreas.indexOf(target.tagName) != -1); + + }; + return callbacks; })({}); \ No newline at end of file diff --git a/modules/caret.js b/modules/caret.js index 156cf75c..53ef9902 100644 --- a/modules/caret.js +++ b/modules/caret.js @@ -49,7 +49,7 @@ module.exports = (function (caret) { } /** If Element is INPUT */ - if (el.tagName == 'INPUT') { + if (el.contentEditable != 'true') { el.focus(); return; diff --git a/modules/toolbar/toolbox.js b/modules/toolbar/toolbox.js index 183876a9..379e2ccd 100644 --- a/modules/toolbar/toolbox.js +++ b/modules/toolbar/toolbox.js @@ -46,6 +46,8 @@ module.exports = (function (toolbox) { /** toolbox state */ editor.toolbar.toolbox.opened = false; + editor.toolbar.current = null; + }; toolbox.leaf = function () { @@ -75,21 +77,14 @@ module.exports = (function (toolbox) { } else { - nextToolIndex = tools.indexOf(currentTool) + 1; + nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length; visibleTool = tools[nextToolIndex]; while (!editor.tools[visibleTool].displayInToolbox) { - nextToolIndex++; + nextToolIndex = (nextToolIndex + 1) % tools.length; visibleTool = tools[nextToolIndex]; - if ( nextToolIndex == tools.length ) { - - nextToolIndex = 0; - visibleTool = tools[nextToolIndex]; - - } - } } diff --git a/modules/ui.js b/modules/ui.js index 31f382c7..283f25ec 100644 --- a/modules/ui.js +++ b/modules/ui.js @@ -351,8 +351,20 @@ module.exports = (function (ui) { var redactor = editor.nodes.redactor; + editor.state.inputs = []; + /** Save all inputs in global variable state */ - editor.state.inputs = redactor.querySelectorAll('[contenteditable], input'); + var inputs = redactor.querySelectorAll('[contenteditable], input, textarea'); + + Array.prototype.map.call(inputs, function (current) { + + if (!current.type || current.type == 'text' || current.type == 'textarea') { + + editor.state.inputs.push(current); + + } + + }); }; diff --git a/package.json b/package.json index a025079b..ba5c2ce1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codex.editor", - "version": "1.5.3", + "version": "1.5.4", "description": "Codex Editor. Native JS, based on API and Open Source", "main": "index.js", "scripts": { diff --git a/plugins/raw/raw-icon-black.svg b/plugins/raw/raw-icon-black.svg new file mode 100644 index 00000000..b9388423 --- /dev/null +++ b/plugins/raw/raw-icon-black.svg @@ -0,0 +1,7 @@ + + RAW + + + + + \ No newline at end of file diff --git a/plugins/raw/raw-icon-white.svg b/plugins/raw/raw-icon-white.svg new file mode 100644 index 00000000..afdf1d24 --- /dev/null +++ b/plugins/raw/raw-icon-white.svg @@ -0,0 +1,7 @@ + + RAW + + + + + \ No newline at end of file diff --git a/plugins/raw/raw.css b/plugins/raw/raw.css new file mode 100644 index 00000000..1af87658 --- /dev/null +++ b/plugins/raw/raw.css @@ -0,0 +1,36 @@ +.raw-plugin__input { + display: block; + width: 100%; + min-height: 200px; + border: 0; + background: #fdfdfd; + box-shadow: inset 0 2px 8px rgba(23, 32, 74, 0.06); + border-radius: 3px; + margin: 1em auto; + padding: 1em; + box-sizing: border-box; + white-space: pre; + outline: none; + resize: vertical; + + font-family: 'monospace', 'monaco', 'consolas', 'courier'; + line-height: 1.7em; + font-size: 12px; + color: #152b48; + overflow: auto; + letter-spacing: 0.015em; +} + +.raw-plugin-icon { + display: inline-block; + width: 16px; + height: 32px; + background: url(raw-icon-black.svg) no-repeat center center; + background-size: contain; +} + +li:hover .raw-plugin-icon, +.selected .raw-plugin-icon{ + background: url(raw-icon-white.svg) no-repeat center center; + background-size: contain; +} diff --git a/plugins/raw/raw.js b/plugins/raw/raw.js new file mode 100644 index 00000000..30b66f60 --- /dev/null +++ b/plugins/raw/raw.js @@ -0,0 +1,51 @@ +/** +* Plugin for CodeX.Editor +* Implements RAW-data block +*/ +var rawPlugin = function (plugin) { + + var editor = codex.editor; + + plugin.render = function (data) { + + var input = editor.draw.node('TEXTAREA', 'raw-plugin__input', {}); + + input.placeholder = 'Вставьте HTML код'; + + if (data && data.html) { + input.value = data.html; + } + + return input; + + }; + + plugin.save = function (block) { + + return { + html: block.value + }; + + }; + + plugin.validate = function (data) { + + if (data.html.trim() === '') { + + return; + + } + + return true; + + }; + + plugin.destroy = function () { + + rawPlugin = null; + + }; + + return plugin; + +}({}); \ No newline at end of file diff --git a/whatwg-fetch.js.map b/whatwg-fetch.js.map index 1205199c..f3ca3c0c 100644 --- a/whatwg-fetch.js.map +++ b/whatwg-fetch.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///whatwg-fetch.js","webpack:///webpack/bootstrap 1c82a22146896c694af5?cbba","webpack:///./~/whatwg-fetch/fetch.js"],"names":["codex","modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","self","normalizeName","name","String","test","TypeError","toLowerCase","normalizeValue","value","iteratorFor","items","iterator","next","shift","done","undefined","support","iterable","Symbol","Headers","headers","this","map","forEach","append","Object","getOwnPropertyNames","consumed","body","bodyUsed","Promise","reject","fileReaderReady","reader","resolve","onload","result","onerror","error","readBlobAsArrayBuffer","blob","FileReader","promise","readAsArrayBuffer","readBlobAsText","readAsText","readArrayBufferAsText","buf","view","Uint8Array","chars","Array","length","i","fromCharCode","join","bufferClone","slice","byteLength","set","buffer","Body","_initBody","_bodyInit","_bodyText","Blob","prototype","isPrototypeOf","_bodyBlob","formData","FormData","_bodyFormData","searchParams","URLSearchParams","toString","arrayBuffer","isDataView","_bodyArrayBuffer","ArrayBuffer","isArrayBufferView","Error","get","type","rejected","then","text","decode","json","JSON","parse","normalizeMethod","method","upcased","toUpperCase","methods","indexOf","Request","input","options","url","credentials","mode","referrer","form","trim","split","bytes","replace","decodeURIComponent","parseHeaders","rawHeaders","line","parts","key","Response","bodyInit","status","ok","statusText","fetch","e","viewClasses","obj","DataView","isView","oldValue","has","hasOwnProperty","callback","thisArg","keys","push","values","entries","clone","response","redirectStatuses","redirect","RangeError","location","init","request","xhr","XMLHttpRequest","getAllResponseHeaders","responseURL","responseText","ontimeout","open","withCredentials","responseType","setRequestHeader","send","polyfill"],"mappings":"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","file":"whatwg-fetch.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) {\n\n\t(function(self) {\n\t 'use strict';\n\t\n\t if (self.fetch) {\n\t return\n\t }\n\t\n\t var support = {\n\t searchParams: 'URLSearchParams' in self,\n\t iterable: 'Symbol' in self && 'iterator' in Symbol,\n\t blob: 'FileReader' in self && 'Blob' in self && (function() {\n\t try {\n\t new Blob()\n\t return true\n\t } catch(e) {\n\t return false\n\t }\n\t })(),\n\t formData: 'FormData' in self,\n\t arrayBuffer: 'ArrayBuffer' in self\n\t }\n\t\n\t if (support.arrayBuffer) {\n\t var viewClasses = [\n\t '[object Int8Array]',\n\t '[object Uint8Array]',\n\t '[object Uint8ClampedArray]',\n\t '[object Int16Array]',\n\t '[object Uint16Array]',\n\t '[object Int32Array]',\n\t '[object Uint32Array]',\n\t '[object Float32Array]',\n\t '[object Float64Array]'\n\t ]\n\t\n\t var isDataView = function(obj) {\n\t return obj && DataView.prototype.isPrototypeOf(obj)\n\t }\n\t\n\t var isArrayBufferView = ArrayBuffer.isView || function(obj) {\n\t return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1\n\t }\n\t }\n\t\n\t function normalizeName(name) {\n\t if (typeof name !== 'string') {\n\t name = String(name)\n\t }\n\t if (/[^a-z0-9\\-#$%&'*+.\\^_`|~]/i.test(name)) {\n\t throw new TypeError('Invalid character in header field name')\n\t }\n\t return name.toLowerCase()\n\t }\n\t\n\t function normalizeValue(value) {\n\t if (typeof value !== 'string') {\n\t value = String(value)\n\t }\n\t return value\n\t }\n\t\n\t // Build a destructive iterator for the value list\n\t function iteratorFor(items) {\n\t var iterator = {\n\t next: function() {\n\t var value = items.shift()\n\t return {done: value === undefined, value: value}\n\t }\n\t }\n\t\n\t if (support.iterable) {\n\t iterator[Symbol.iterator] = function() {\n\t return iterator\n\t }\n\t }\n\t\n\t return iterator\n\t }\n\t\n\t function Headers(headers) {\n\t this.map = {}\n\t\n\t if (headers instanceof Headers) {\n\t headers.forEach(function(value, name) {\n\t this.append(name, value)\n\t }, this)\n\t\n\t } else if (headers) {\n\t Object.getOwnPropertyNames(headers).forEach(function(name) {\n\t this.append(name, headers[name])\n\t }, this)\n\t }\n\t }\n\t\n\t Headers.prototype.append = function(name, value) {\n\t name = normalizeName(name)\n\t value = normalizeValue(value)\n\t var oldValue = this.map[name]\n\t this.map[name] = oldValue ? oldValue+','+value : value\n\t }\n\t\n\t Headers.prototype['delete'] = function(name) {\n\t delete this.map[normalizeName(name)]\n\t }\n\t\n\t Headers.prototype.get = function(name) {\n\t name = normalizeName(name)\n\t return this.has(name) ? this.map[name] : null\n\t }\n\t\n\t Headers.prototype.has = function(name) {\n\t return this.map.hasOwnProperty(normalizeName(name))\n\t }\n\t\n\t Headers.prototype.set = function(name, value) {\n\t this.map[normalizeName(name)] = normalizeValue(value)\n\t }\n\t\n\t Headers.prototype.forEach = function(callback, thisArg) {\n\t for (var name in this.map) {\n\t if (this.map.hasOwnProperty(name)) {\n\t callback.call(thisArg, this.map[name], name, this)\n\t }\n\t }\n\t }\n\t\n\t Headers.prototype.keys = function() {\n\t var items = []\n\t this.forEach(function(value, name) { items.push(name) })\n\t return iteratorFor(items)\n\t }\n\t\n\t Headers.prototype.values = function() {\n\t var items = []\n\t this.forEach(function(value) { items.push(value) })\n\t return iteratorFor(items)\n\t }\n\t\n\t Headers.prototype.entries = function() {\n\t var items = []\n\t this.forEach(function(value, name) { items.push([name, value]) })\n\t return iteratorFor(items)\n\t }\n\t\n\t if (support.iterable) {\n\t Headers.prototype[Symbol.iterator] = Headers.prototype.entries\n\t }\n\t\n\t function consumed(body) {\n\t if (body.bodyUsed) {\n\t return Promise.reject(new TypeError('Already read'))\n\t }\n\t body.bodyUsed = true\n\t }\n\t\n\t function fileReaderReady(reader) {\n\t return new Promise(function(resolve, reject) {\n\t reader.onload = function() {\n\t resolve(reader.result)\n\t }\n\t reader.onerror = function() {\n\t reject(reader.error)\n\t }\n\t })\n\t }\n\t\n\t function readBlobAsArrayBuffer(blob) {\n\t var reader = new FileReader()\n\t var promise = fileReaderReady(reader)\n\t reader.readAsArrayBuffer(blob)\n\t return promise\n\t }\n\t\n\t function readBlobAsText(blob) {\n\t var reader = new FileReader()\n\t var promise = fileReaderReady(reader)\n\t reader.readAsText(blob)\n\t return promise\n\t }\n\t\n\t function readArrayBufferAsText(buf) {\n\t var view = new Uint8Array(buf)\n\t var chars = new Array(view.length)\n\t\n\t for (var i = 0; i < view.length; i++) {\n\t chars[i] = String.fromCharCode(view[i])\n\t }\n\t return chars.join('')\n\t }\n\t\n\t function bufferClone(buf) {\n\t if (buf.slice) {\n\t return buf.slice(0)\n\t } else {\n\t var view = new Uint8Array(buf.byteLength)\n\t view.set(new Uint8Array(buf))\n\t return view.buffer\n\t }\n\t }\n\t\n\t function Body() {\n\t this.bodyUsed = false\n\t\n\t this._initBody = function(body) {\n\t this._bodyInit = body\n\t if (!body) {\n\t this._bodyText = ''\n\t } else if (typeof body === 'string') {\n\t this._bodyText = body\n\t } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {\n\t this._bodyBlob = body\n\t } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {\n\t this._bodyFormData = body\n\t } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n\t this._bodyText = body.toString()\n\t } else if (support.arrayBuffer && support.blob && isDataView(body)) {\n\t this._bodyArrayBuffer = bufferClone(body.buffer)\n\t // IE 10-11 can't handle a DataView body.\n\t this._bodyInit = new Blob([this._bodyArrayBuffer])\n\t } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {\n\t this._bodyArrayBuffer = bufferClone(body)\n\t } else {\n\t throw new Error('unsupported BodyInit type')\n\t }\n\t\n\t if (!this.headers.get('content-type')) {\n\t if (typeof body === 'string') {\n\t this.headers.set('content-type', 'text/plain;charset=UTF-8')\n\t } else if (this._bodyBlob && this._bodyBlob.type) {\n\t this.headers.set('content-type', this._bodyBlob.type)\n\t } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n\t this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')\n\t }\n\t }\n\t }\n\t\n\t if (support.blob) {\n\t this.blob = function() {\n\t var rejected = consumed(this)\n\t if (rejected) {\n\t return rejected\n\t }\n\t\n\t if (this._bodyBlob) {\n\t return Promise.resolve(this._bodyBlob)\n\t } else if (this._bodyArrayBuffer) {\n\t return Promise.resolve(new Blob([this._bodyArrayBuffer]))\n\t } else if (this._bodyFormData) {\n\t throw new Error('could not read FormData body as blob')\n\t } else {\n\t return Promise.resolve(new Blob([this._bodyText]))\n\t }\n\t }\n\t\n\t this.arrayBuffer = function() {\n\t if (this._bodyArrayBuffer) {\n\t return consumed(this) || Promise.resolve(this._bodyArrayBuffer)\n\t } else {\n\t return this.blob().then(readBlobAsArrayBuffer)\n\t }\n\t }\n\t }\n\t\n\t this.text = function() {\n\t var rejected = consumed(this)\n\t if (rejected) {\n\t return rejected\n\t }\n\t\n\t if (this._bodyBlob) {\n\t return readBlobAsText(this._bodyBlob)\n\t } else if (this._bodyArrayBuffer) {\n\t return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))\n\t } else if (this._bodyFormData) {\n\t throw new Error('could not read FormData body as text')\n\t } else {\n\t return Promise.resolve(this._bodyText)\n\t }\n\t }\n\t\n\t if (support.formData) {\n\t this.formData = function() {\n\t return this.text().then(decode)\n\t }\n\t }\n\t\n\t this.json = function() {\n\t return this.text().then(JSON.parse)\n\t }\n\t\n\t return this\n\t }\n\t\n\t // HTTP methods whose capitalization should be normalized\n\t var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']\n\t\n\t function normalizeMethod(method) {\n\t var upcased = method.toUpperCase()\n\t return (methods.indexOf(upcased) > -1) ? upcased : method\n\t }\n\t\n\t function Request(input, options) {\n\t options = options || {}\n\t var body = options.body\n\t\n\t if (input instanceof Request) {\n\t if (input.bodyUsed) {\n\t throw new TypeError('Already read')\n\t }\n\t this.url = input.url\n\t this.credentials = input.credentials\n\t if (!options.headers) {\n\t this.headers = new Headers(input.headers)\n\t }\n\t this.method = input.method\n\t this.mode = input.mode\n\t if (!body && input._bodyInit != null) {\n\t body = input._bodyInit\n\t input.bodyUsed = true\n\t }\n\t } else {\n\t this.url = String(input)\n\t }\n\t\n\t this.credentials = options.credentials || this.credentials || 'omit'\n\t if (options.headers || !this.headers) {\n\t this.headers = new Headers(options.headers)\n\t }\n\t this.method = normalizeMethod(options.method || this.method || 'GET')\n\t this.mode = options.mode || this.mode || null\n\t this.referrer = null\n\t\n\t if ((this.method === 'GET' || this.method === 'HEAD') && body) {\n\t throw new TypeError('Body not allowed for GET or HEAD requests')\n\t }\n\t this._initBody(body)\n\t }\n\t\n\t Request.prototype.clone = function() {\n\t return new Request(this, { body: this._bodyInit })\n\t }\n\t\n\t function decode(body) {\n\t var form = new FormData()\n\t body.trim().split('&').forEach(function(bytes) {\n\t if (bytes) {\n\t var split = bytes.split('=')\n\t var name = split.shift().replace(/\\+/g, ' ')\n\t var value = split.join('=').replace(/\\+/g, ' ')\n\t form.append(decodeURIComponent(name), decodeURIComponent(value))\n\t }\n\t })\n\t return form\n\t }\n\t\n\t function parseHeaders(rawHeaders) {\n\t var headers = new Headers()\n\t rawHeaders.split(/\\r?\\n/).forEach(function(line) {\n\t var parts = line.split(':')\n\t var key = parts.shift().trim()\n\t if (key) {\n\t var value = parts.join(':').trim()\n\t headers.append(key, value)\n\t }\n\t })\n\t return headers\n\t }\n\t\n\t Body.call(Request.prototype)\n\t\n\t function Response(bodyInit, options) {\n\t if (!options) {\n\t options = {}\n\t }\n\t\n\t this.type = 'default'\n\t this.status = 'status' in options ? options.status : 200\n\t this.ok = this.status >= 200 && this.status < 300\n\t this.statusText = 'statusText' in options ? options.statusText : 'OK'\n\t this.headers = new Headers(options.headers)\n\t this.url = options.url || ''\n\t this._initBody(bodyInit)\n\t }\n\t\n\t Body.call(Response.prototype)\n\t\n\t Response.prototype.clone = function() {\n\t return new Response(this._bodyInit, {\n\t status: this.status,\n\t statusText: this.statusText,\n\t headers: new Headers(this.headers),\n\t url: this.url\n\t })\n\t }\n\t\n\t Response.error = function() {\n\t var response = new Response(null, {status: 0, statusText: ''})\n\t response.type = 'error'\n\t return response\n\t }\n\t\n\t var redirectStatuses = [301, 302, 303, 307, 308]\n\t\n\t Response.redirect = function(url, status) {\n\t if (redirectStatuses.indexOf(status) === -1) {\n\t throw new RangeError('Invalid status code')\n\t }\n\t\n\t return new Response(null, {status: status, headers: {location: url}})\n\t }\n\t\n\t self.Headers = Headers\n\t self.Request = Request\n\t self.Response = Response\n\t\n\t self.fetch = function(input, init) {\n\t return new Promise(function(resolve, reject) {\n\t var request = new Request(input, init)\n\t var xhr = new XMLHttpRequest()\n\t\n\t xhr.onload = function() {\n\t var options = {\n\t status: xhr.status,\n\t statusText: xhr.statusText,\n\t headers: parseHeaders(xhr.getAllResponseHeaders() || '')\n\t }\n\t options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')\n\t var body = 'response' in xhr ? xhr.response : xhr.responseText\n\t resolve(new Response(body, options))\n\t }\n\t\n\t xhr.onerror = function() {\n\t reject(new TypeError('Network request failed'))\n\t }\n\t\n\t xhr.ontimeout = function() {\n\t reject(new TypeError('Network request failed'))\n\t }\n\t\n\t xhr.open(request.method, request.url, true)\n\t\n\t if (request.credentials === 'include') {\n\t xhr.withCredentials = true\n\t }\n\t\n\t if ('responseType' in xhr && support.blob) {\n\t xhr.responseType = 'blob'\n\t }\n\t\n\t request.headers.forEach(function(value, name) {\n\t xhr.setRequestHeader(name, value)\n\t })\n\t\n\t xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)\n\t })\n\t }\n\t self.fetch.polyfill = true\n\t})(typeof self !== 'undefined' ? self : this);\n\n\n/***/ }\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// whatwg-fetch.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 1c82a22146896c694af5","(function(self) {\n 'use strict';\n\n if (self.fetch) {\n return\n }\n\n var support = {\n searchParams: 'URLSearchParams' in self,\n iterable: 'Symbol' in self && 'iterator' in Symbol,\n blob: 'FileReader' in self && 'Blob' in self && (function() {\n try {\n new Blob()\n return true\n } catch(e) {\n return false\n }\n })(),\n formData: 'FormData' in self,\n arrayBuffer: 'ArrayBuffer' in self\n }\n\n if (support.arrayBuffer) {\n var viewClasses = [\n '[object Int8Array]',\n '[object Uint8Array]',\n '[object Uint8ClampedArray]',\n '[object Int16Array]',\n '[object Uint16Array]',\n '[object Int32Array]',\n '[object Uint32Array]',\n '[object Float32Array]',\n '[object Float64Array]'\n ]\n\n var isDataView = function(obj) {\n return obj && DataView.prototype.isPrototypeOf(obj)\n }\n\n var isArrayBufferView = ArrayBuffer.isView || function(obj) {\n return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1\n }\n }\n\n function normalizeName(name) {\n if (typeof name !== 'string') {\n name = String(name)\n }\n if (/[^a-z0-9\\-#$%&'*+.\\^_`|~]/i.test(name)) {\n throw new TypeError('Invalid character in header field name')\n }\n return name.toLowerCase()\n }\n\n function normalizeValue(value) {\n if (typeof value !== 'string') {\n value = String(value)\n }\n return value\n }\n\n // Build a destructive iterator for the value list\n function iteratorFor(items) {\n var iterator = {\n next: function() {\n var value = items.shift()\n return {done: value === undefined, value: value}\n }\n }\n\n if (support.iterable) {\n iterator[Symbol.iterator] = function() {\n return iterator\n }\n }\n\n return iterator\n }\n\n function Headers(headers) {\n this.map = {}\n\n if (headers instanceof Headers) {\n headers.forEach(function(value, name) {\n this.append(name, value)\n }, this)\n\n } else if (headers) {\n Object.getOwnPropertyNames(headers).forEach(function(name) {\n this.append(name, headers[name])\n }, this)\n }\n }\n\n Headers.prototype.append = function(name, value) {\n name = normalizeName(name)\n value = normalizeValue(value)\n var oldValue = this.map[name]\n this.map[name] = oldValue ? oldValue+','+value : value\n }\n\n Headers.prototype['delete'] = function(name) {\n delete this.map[normalizeName(name)]\n }\n\n Headers.prototype.get = function(name) {\n name = normalizeName(name)\n return this.has(name) ? this.map[name] : null\n }\n\n Headers.prototype.has = function(name) {\n return this.map.hasOwnProperty(normalizeName(name))\n }\n\n Headers.prototype.set = function(name, value) {\n this.map[normalizeName(name)] = normalizeValue(value)\n }\n\n Headers.prototype.forEach = function(callback, thisArg) {\n for (var name in this.map) {\n if (this.map.hasOwnProperty(name)) {\n callback.call(thisArg, this.map[name], name, this)\n }\n }\n }\n\n Headers.prototype.keys = function() {\n var items = []\n this.forEach(function(value, name) { items.push(name) })\n return iteratorFor(items)\n }\n\n Headers.prototype.values = function() {\n var items = []\n this.forEach(function(value) { items.push(value) })\n return iteratorFor(items)\n }\n\n Headers.prototype.entries = function() {\n var items = []\n this.forEach(function(value, name) { items.push([name, value]) })\n return iteratorFor(items)\n }\n\n if (support.iterable) {\n Headers.prototype[Symbol.iterator] = Headers.prototype.entries\n }\n\n function consumed(body) {\n if (body.bodyUsed) {\n return Promise.reject(new TypeError('Already read'))\n }\n body.bodyUsed = true\n }\n\n function fileReaderReady(reader) {\n return new Promise(function(resolve, reject) {\n reader.onload = function() {\n resolve(reader.result)\n }\n reader.onerror = function() {\n reject(reader.error)\n }\n })\n }\n\n function readBlobAsArrayBuffer(blob) {\n var reader = new FileReader()\n var promise = fileReaderReady(reader)\n reader.readAsArrayBuffer(blob)\n return promise\n }\n\n function readBlobAsText(blob) {\n var reader = new FileReader()\n var promise = fileReaderReady(reader)\n reader.readAsText(blob)\n return promise\n }\n\n function readArrayBufferAsText(buf) {\n var view = new Uint8Array(buf)\n var chars = new Array(view.length)\n\n for (var i = 0; i < view.length; i++) {\n chars[i] = String.fromCharCode(view[i])\n }\n return chars.join('')\n }\n\n function bufferClone(buf) {\n if (buf.slice) {\n return buf.slice(0)\n } else {\n var view = new Uint8Array(buf.byteLength)\n view.set(new Uint8Array(buf))\n return view.buffer\n }\n }\n\n function Body() {\n this.bodyUsed = false\n\n this._initBody = function(body) {\n this._bodyInit = body\n if (!body) {\n this._bodyText = ''\n } else if (typeof body === 'string') {\n this._bodyText = body\n } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {\n this._bodyBlob = body\n } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {\n this._bodyFormData = body\n } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n this._bodyText = body.toString()\n } else if (support.arrayBuffer && support.blob && isDataView(body)) {\n this._bodyArrayBuffer = bufferClone(body.buffer)\n // IE 10-11 can't handle a DataView body.\n this._bodyInit = new Blob([this._bodyArrayBuffer])\n } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {\n this._bodyArrayBuffer = bufferClone(body)\n } else {\n throw new Error('unsupported BodyInit type')\n }\n\n if (!this.headers.get('content-type')) {\n if (typeof body === 'string') {\n this.headers.set('content-type', 'text/plain;charset=UTF-8')\n } else if (this._bodyBlob && this._bodyBlob.type) {\n this.headers.set('content-type', this._bodyBlob.type)\n } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')\n }\n }\n }\n\n if (support.blob) {\n this.blob = function() {\n var rejected = consumed(this)\n if (rejected) {\n return rejected\n }\n\n if (this._bodyBlob) {\n return Promise.resolve(this._bodyBlob)\n } else if (this._bodyArrayBuffer) {\n return Promise.resolve(new Blob([this._bodyArrayBuffer]))\n } else if (this._bodyFormData) {\n throw new Error('could not read FormData body as blob')\n } else {\n return Promise.resolve(new Blob([this._bodyText]))\n }\n }\n\n this.arrayBuffer = function() {\n if (this._bodyArrayBuffer) {\n return consumed(this) || Promise.resolve(this._bodyArrayBuffer)\n } else {\n return this.blob().then(readBlobAsArrayBuffer)\n }\n }\n }\n\n this.text = function() {\n var rejected = consumed(this)\n if (rejected) {\n return rejected\n }\n\n if (this._bodyBlob) {\n return readBlobAsText(this._bodyBlob)\n } else if (this._bodyArrayBuffer) {\n return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))\n } else if (this._bodyFormData) {\n throw new Error('could not read FormData body as text')\n } else {\n return Promise.resolve(this._bodyText)\n }\n }\n\n if (support.formData) {\n this.formData = function() {\n return this.text().then(decode)\n }\n }\n\n this.json = function() {\n return this.text().then(JSON.parse)\n }\n\n return this\n }\n\n // HTTP methods whose capitalization should be normalized\n var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']\n\n function normalizeMethod(method) {\n var upcased = method.toUpperCase()\n return (methods.indexOf(upcased) > -1) ? upcased : method\n }\n\n function Request(input, options) {\n options = options || {}\n var body = options.body\n\n if (input instanceof Request) {\n if (input.bodyUsed) {\n throw new TypeError('Already read')\n }\n this.url = input.url\n this.credentials = input.credentials\n if (!options.headers) {\n this.headers = new Headers(input.headers)\n }\n this.method = input.method\n this.mode = input.mode\n if (!body && input._bodyInit != null) {\n body = input._bodyInit\n input.bodyUsed = true\n }\n } else {\n this.url = String(input)\n }\n\n this.credentials = options.credentials || this.credentials || 'omit'\n if (options.headers || !this.headers) {\n this.headers = new Headers(options.headers)\n }\n this.method = normalizeMethod(options.method || this.method || 'GET')\n this.mode = options.mode || this.mode || null\n this.referrer = null\n\n if ((this.method === 'GET' || this.method === 'HEAD') && body) {\n throw new TypeError('Body not allowed for GET or HEAD requests')\n }\n this._initBody(body)\n }\n\n Request.prototype.clone = function() {\n return new Request(this, { body: this._bodyInit })\n }\n\n function decode(body) {\n var form = new FormData()\n body.trim().split('&').forEach(function(bytes) {\n if (bytes) {\n var split = bytes.split('=')\n var name = split.shift().replace(/\\+/g, ' ')\n var value = split.join('=').replace(/\\+/g, ' ')\n form.append(decodeURIComponent(name), decodeURIComponent(value))\n }\n })\n return form\n }\n\n function parseHeaders(rawHeaders) {\n var headers = new Headers()\n rawHeaders.split(/\\r?\\n/).forEach(function(line) {\n var parts = line.split(':')\n var key = parts.shift().trim()\n if (key) {\n var value = parts.join(':').trim()\n headers.append(key, value)\n }\n })\n return headers\n }\n\n Body.call(Request.prototype)\n\n function Response(bodyInit, options) {\n if (!options) {\n options = {}\n }\n\n this.type = 'default'\n this.status = 'status' in options ? options.status : 200\n this.ok = this.status >= 200 && this.status < 300\n this.statusText = 'statusText' in options ? options.statusText : 'OK'\n this.headers = new Headers(options.headers)\n this.url = options.url || ''\n this._initBody(bodyInit)\n }\n\n Body.call(Response.prototype)\n\n Response.prototype.clone = function() {\n return new Response(this._bodyInit, {\n status: this.status,\n statusText: this.statusText,\n headers: new Headers(this.headers),\n url: this.url\n })\n }\n\n Response.error = function() {\n var response = new Response(null, {status: 0, statusText: ''})\n response.type = 'error'\n return response\n }\n\n var redirectStatuses = [301, 302, 303, 307, 308]\n\n Response.redirect = function(url, status) {\n if (redirectStatuses.indexOf(status) === -1) {\n throw new RangeError('Invalid status code')\n }\n\n return new Response(null, {status: status, headers: {location: url}})\n }\n\n self.Headers = Headers\n self.Request = Request\n self.Response = Response\n\n self.fetch = function(input, init) {\n return new Promise(function(resolve, reject) {\n var request = new Request(input, init)\n var xhr = new XMLHttpRequest()\n\n xhr.onload = function() {\n var options = {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: parseHeaders(xhr.getAllResponseHeaders() || '')\n }\n options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')\n var body = 'response' in xhr ? xhr.response : xhr.responseText\n resolve(new Response(body, options))\n }\n\n xhr.onerror = function() {\n reject(new TypeError('Network request failed'))\n }\n\n xhr.ontimeout = function() {\n reject(new TypeError('Network request failed'))\n }\n\n xhr.open(request.method, request.url, true)\n\n if (request.credentials === 'include') {\n xhr.withCredentials = true\n }\n\n if ('responseType' in xhr && support.blob) {\n xhr.responseType = 'blob'\n }\n\n request.headers.forEach(function(value, name) {\n xhr.setRequestHeader(name, value)\n })\n\n xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)\n })\n }\n self.fetch.polyfill = true\n})(typeof self !== 'undefined' ? self : this);\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/whatwg-fetch/fetch.js\n// module id = 0\n// module chunks = 1"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///whatwg-fetch.js","webpack:///webpack/bootstrap d53b65d3ebbd53c620c1?cf88","webpack:///./~/whatwg-fetch/fetch.js"],"names":["codex","modules","__webpack_require__","moduleId","installedModules","exports","module","id","loaded","call","m","c","p","self","normalizeName","name","String","test","TypeError","toLowerCase","normalizeValue","value","iteratorFor","items","iterator","next","shift","done","undefined","support","iterable","Symbol","Headers","headers","this","map","forEach","append","Object","getOwnPropertyNames","consumed","body","bodyUsed","Promise","reject","fileReaderReady","reader","resolve","onload","result","onerror","error","readBlobAsArrayBuffer","blob","FileReader","promise","readAsArrayBuffer","readBlobAsText","readAsText","readArrayBufferAsText","buf","view","Uint8Array","chars","Array","length","i","fromCharCode","join","bufferClone","slice","byteLength","set","buffer","Body","_initBody","_bodyInit","_bodyText","Blob","prototype","isPrototypeOf","_bodyBlob","formData","FormData","_bodyFormData","searchParams","URLSearchParams","toString","arrayBuffer","isDataView","_bodyArrayBuffer","ArrayBuffer","isArrayBufferView","Error","get","type","rejected","then","text","decode","json","JSON","parse","normalizeMethod","method","upcased","toUpperCase","methods","indexOf","Request","input","options","url","credentials","mode","referrer","form","trim","split","bytes","replace","decodeURIComponent","parseHeaders","rawHeaders","line","parts","key","Response","bodyInit","status","ok","statusText","fetch","e","viewClasses","obj","DataView","isView","oldValue","has","hasOwnProperty","callback","thisArg","keys","push","values","entries","clone","response","redirectStatuses","redirect","RangeError","location","init","request","xhr","XMLHttpRequest","getAllResponseHeaders","responseURL","responseText","ontimeout","open","withCredentials","responseType","setRequestHeader","send","polyfill"],"mappings":"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","file":"whatwg-fetch.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) {\n\n\t(function(self) {\n\t 'use strict';\n\t\n\t if (self.fetch) {\n\t return\n\t }\n\t\n\t var support = {\n\t searchParams: 'URLSearchParams' in self,\n\t iterable: 'Symbol' in self && 'iterator' in Symbol,\n\t blob: 'FileReader' in self && 'Blob' in self && (function() {\n\t try {\n\t new Blob()\n\t return true\n\t } catch(e) {\n\t return false\n\t }\n\t })(),\n\t formData: 'FormData' in self,\n\t arrayBuffer: 'ArrayBuffer' in self\n\t }\n\t\n\t if (support.arrayBuffer) {\n\t var viewClasses = [\n\t '[object Int8Array]',\n\t '[object Uint8Array]',\n\t '[object Uint8ClampedArray]',\n\t '[object Int16Array]',\n\t '[object Uint16Array]',\n\t '[object Int32Array]',\n\t '[object Uint32Array]',\n\t '[object Float32Array]',\n\t '[object Float64Array]'\n\t ]\n\t\n\t var isDataView = function(obj) {\n\t return obj && DataView.prototype.isPrototypeOf(obj)\n\t }\n\t\n\t var isArrayBufferView = ArrayBuffer.isView || function(obj) {\n\t return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1\n\t }\n\t }\n\t\n\t function normalizeName(name) {\n\t if (typeof name !== 'string') {\n\t name = String(name)\n\t }\n\t if (/[^a-z0-9\\-#$%&'*+.\\^_`|~]/i.test(name)) {\n\t throw new TypeError('Invalid character in header field name')\n\t }\n\t return name.toLowerCase()\n\t }\n\t\n\t function normalizeValue(value) {\n\t if (typeof value !== 'string') {\n\t value = String(value)\n\t }\n\t return value\n\t }\n\t\n\t // Build a destructive iterator for the value list\n\t function iteratorFor(items) {\n\t var iterator = {\n\t next: function() {\n\t var value = items.shift()\n\t return {done: value === undefined, value: value}\n\t }\n\t }\n\t\n\t if (support.iterable) {\n\t iterator[Symbol.iterator] = function() {\n\t return iterator\n\t }\n\t }\n\t\n\t return iterator\n\t }\n\t\n\t function Headers(headers) {\n\t this.map = {}\n\t\n\t if (headers instanceof Headers) {\n\t headers.forEach(function(value, name) {\n\t this.append(name, value)\n\t }, this)\n\t\n\t } else if (headers) {\n\t Object.getOwnPropertyNames(headers).forEach(function(name) {\n\t this.append(name, headers[name])\n\t }, this)\n\t }\n\t }\n\t\n\t Headers.prototype.append = function(name, value) {\n\t name = normalizeName(name)\n\t value = normalizeValue(value)\n\t var oldValue = this.map[name]\n\t this.map[name] = oldValue ? oldValue+','+value : value\n\t }\n\t\n\t Headers.prototype['delete'] = function(name) {\n\t delete this.map[normalizeName(name)]\n\t }\n\t\n\t Headers.prototype.get = function(name) {\n\t name = normalizeName(name)\n\t return this.has(name) ? this.map[name] : null\n\t }\n\t\n\t Headers.prototype.has = function(name) {\n\t return this.map.hasOwnProperty(normalizeName(name))\n\t }\n\t\n\t Headers.prototype.set = function(name, value) {\n\t this.map[normalizeName(name)] = normalizeValue(value)\n\t }\n\t\n\t Headers.prototype.forEach = function(callback, thisArg) {\n\t for (var name in this.map) {\n\t if (this.map.hasOwnProperty(name)) {\n\t callback.call(thisArg, this.map[name], name, this)\n\t }\n\t }\n\t }\n\t\n\t Headers.prototype.keys = function() {\n\t var items = []\n\t this.forEach(function(value, name) { items.push(name) })\n\t return iteratorFor(items)\n\t }\n\t\n\t Headers.prototype.values = function() {\n\t var items = []\n\t this.forEach(function(value) { items.push(value) })\n\t return iteratorFor(items)\n\t }\n\t\n\t Headers.prototype.entries = function() {\n\t var items = []\n\t this.forEach(function(value, name) { items.push([name, value]) })\n\t return iteratorFor(items)\n\t }\n\t\n\t if (support.iterable) {\n\t Headers.prototype[Symbol.iterator] = Headers.prototype.entries\n\t }\n\t\n\t function consumed(body) {\n\t if (body.bodyUsed) {\n\t return Promise.reject(new TypeError('Already read'))\n\t }\n\t body.bodyUsed = true\n\t }\n\t\n\t function fileReaderReady(reader) {\n\t return new Promise(function(resolve, reject) {\n\t reader.onload = function() {\n\t resolve(reader.result)\n\t }\n\t reader.onerror = function() {\n\t reject(reader.error)\n\t }\n\t })\n\t }\n\t\n\t function readBlobAsArrayBuffer(blob) {\n\t var reader = new FileReader()\n\t var promise = fileReaderReady(reader)\n\t reader.readAsArrayBuffer(blob)\n\t return promise\n\t }\n\t\n\t function readBlobAsText(blob) {\n\t var reader = new FileReader()\n\t var promise = fileReaderReady(reader)\n\t reader.readAsText(blob)\n\t return promise\n\t }\n\t\n\t function readArrayBufferAsText(buf) {\n\t var view = new Uint8Array(buf)\n\t var chars = new Array(view.length)\n\t\n\t for (var i = 0; i < view.length; i++) {\n\t chars[i] = String.fromCharCode(view[i])\n\t }\n\t return chars.join('')\n\t }\n\t\n\t function bufferClone(buf) {\n\t if (buf.slice) {\n\t return buf.slice(0)\n\t } else {\n\t var view = new Uint8Array(buf.byteLength)\n\t view.set(new Uint8Array(buf))\n\t return view.buffer\n\t }\n\t }\n\t\n\t function Body() {\n\t this.bodyUsed = false\n\t\n\t this._initBody = function(body) {\n\t this._bodyInit = body\n\t if (!body) {\n\t this._bodyText = ''\n\t } else if (typeof body === 'string') {\n\t this._bodyText = body\n\t } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {\n\t this._bodyBlob = body\n\t } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {\n\t this._bodyFormData = body\n\t } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n\t this._bodyText = body.toString()\n\t } else if (support.arrayBuffer && support.blob && isDataView(body)) {\n\t this._bodyArrayBuffer = bufferClone(body.buffer)\n\t // IE 10-11 can't handle a DataView body.\n\t this._bodyInit = new Blob([this._bodyArrayBuffer])\n\t } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {\n\t this._bodyArrayBuffer = bufferClone(body)\n\t } else {\n\t throw new Error('unsupported BodyInit type')\n\t }\n\t\n\t if (!this.headers.get('content-type')) {\n\t if (typeof body === 'string') {\n\t this.headers.set('content-type', 'text/plain;charset=UTF-8')\n\t } else if (this._bodyBlob && this._bodyBlob.type) {\n\t this.headers.set('content-type', this._bodyBlob.type)\n\t } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n\t this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')\n\t }\n\t }\n\t }\n\t\n\t if (support.blob) {\n\t this.blob = function() {\n\t var rejected = consumed(this)\n\t if (rejected) {\n\t return rejected\n\t }\n\t\n\t if (this._bodyBlob) {\n\t return Promise.resolve(this._bodyBlob)\n\t } else if (this._bodyArrayBuffer) {\n\t return Promise.resolve(new Blob([this._bodyArrayBuffer]))\n\t } else if (this._bodyFormData) {\n\t throw new Error('could not read FormData body as blob')\n\t } else {\n\t return Promise.resolve(new Blob([this._bodyText]))\n\t }\n\t }\n\t\n\t this.arrayBuffer = function() {\n\t if (this._bodyArrayBuffer) {\n\t return consumed(this) || Promise.resolve(this._bodyArrayBuffer)\n\t } else {\n\t return this.blob().then(readBlobAsArrayBuffer)\n\t }\n\t }\n\t }\n\t\n\t this.text = function() {\n\t var rejected = consumed(this)\n\t if (rejected) {\n\t return rejected\n\t }\n\t\n\t if (this._bodyBlob) {\n\t return readBlobAsText(this._bodyBlob)\n\t } else if (this._bodyArrayBuffer) {\n\t return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))\n\t } else if (this._bodyFormData) {\n\t throw new Error('could not read FormData body as text')\n\t } else {\n\t return Promise.resolve(this._bodyText)\n\t }\n\t }\n\t\n\t if (support.formData) {\n\t this.formData = function() {\n\t return this.text().then(decode)\n\t }\n\t }\n\t\n\t this.json = function() {\n\t return this.text().then(JSON.parse)\n\t }\n\t\n\t return this\n\t }\n\t\n\t // HTTP methods whose capitalization should be normalized\n\t var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']\n\t\n\t function normalizeMethod(method) {\n\t var upcased = method.toUpperCase()\n\t return (methods.indexOf(upcased) > -1) ? upcased : method\n\t }\n\t\n\t function Request(input, options) {\n\t options = options || {}\n\t var body = options.body\n\t\n\t if (input instanceof Request) {\n\t if (input.bodyUsed) {\n\t throw new TypeError('Already read')\n\t }\n\t this.url = input.url\n\t this.credentials = input.credentials\n\t if (!options.headers) {\n\t this.headers = new Headers(input.headers)\n\t }\n\t this.method = input.method\n\t this.mode = input.mode\n\t if (!body && input._bodyInit != null) {\n\t body = input._bodyInit\n\t input.bodyUsed = true\n\t }\n\t } else {\n\t this.url = String(input)\n\t }\n\t\n\t this.credentials = options.credentials || this.credentials || 'omit'\n\t if (options.headers || !this.headers) {\n\t this.headers = new Headers(options.headers)\n\t }\n\t this.method = normalizeMethod(options.method || this.method || 'GET')\n\t this.mode = options.mode || this.mode || null\n\t this.referrer = null\n\t\n\t if ((this.method === 'GET' || this.method === 'HEAD') && body) {\n\t throw new TypeError('Body not allowed for GET or HEAD requests')\n\t }\n\t this._initBody(body)\n\t }\n\t\n\t Request.prototype.clone = function() {\n\t return new Request(this, { body: this._bodyInit })\n\t }\n\t\n\t function decode(body) {\n\t var form = new FormData()\n\t body.trim().split('&').forEach(function(bytes) {\n\t if (bytes) {\n\t var split = bytes.split('=')\n\t var name = split.shift().replace(/\\+/g, ' ')\n\t var value = split.join('=').replace(/\\+/g, ' ')\n\t form.append(decodeURIComponent(name), decodeURIComponent(value))\n\t }\n\t })\n\t return form\n\t }\n\t\n\t function parseHeaders(rawHeaders) {\n\t var headers = new Headers()\n\t rawHeaders.split(/\\r?\\n/).forEach(function(line) {\n\t var parts = line.split(':')\n\t var key = parts.shift().trim()\n\t if (key) {\n\t var value = parts.join(':').trim()\n\t headers.append(key, value)\n\t }\n\t })\n\t return headers\n\t }\n\t\n\t Body.call(Request.prototype)\n\t\n\t function Response(bodyInit, options) {\n\t if (!options) {\n\t options = {}\n\t }\n\t\n\t this.type = 'default'\n\t this.status = 'status' in options ? options.status : 200\n\t this.ok = this.status >= 200 && this.status < 300\n\t this.statusText = 'statusText' in options ? options.statusText : 'OK'\n\t this.headers = new Headers(options.headers)\n\t this.url = options.url || ''\n\t this._initBody(bodyInit)\n\t }\n\t\n\t Body.call(Response.prototype)\n\t\n\t Response.prototype.clone = function() {\n\t return new Response(this._bodyInit, {\n\t status: this.status,\n\t statusText: this.statusText,\n\t headers: new Headers(this.headers),\n\t url: this.url\n\t })\n\t }\n\t\n\t Response.error = function() {\n\t var response = new Response(null, {status: 0, statusText: ''})\n\t response.type = 'error'\n\t return response\n\t }\n\t\n\t var redirectStatuses = [301, 302, 303, 307, 308]\n\t\n\t Response.redirect = function(url, status) {\n\t if (redirectStatuses.indexOf(status) === -1) {\n\t throw new RangeError('Invalid status code')\n\t }\n\t\n\t return new Response(null, {status: status, headers: {location: url}})\n\t }\n\t\n\t self.Headers = Headers\n\t self.Request = Request\n\t self.Response = Response\n\t\n\t self.fetch = function(input, init) {\n\t return new Promise(function(resolve, reject) {\n\t var request = new Request(input, init)\n\t var xhr = new XMLHttpRequest()\n\t\n\t xhr.onload = function() {\n\t var options = {\n\t status: xhr.status,\n\t statusText: xhr.statusText,\n\t headers: parseHeaders(xhr.getAllResponseHeaders() || '')\n\t }\n\t options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')\n\t var body = 'response' in xhr ? xhr.response : xhr.responseText\n\t resolve(new Response(body, options))\n\t }\n\t\n\t xhr.onerror = function() {\n\t reject(new TypeError('Network request failed'))\n\t }\n\t\n\t xhr.ontimeout = function() {\n\t reject(new TypeError('Network request failed'))\n\t }\n\t\n\t xhr.open(request.method, request.url, true)\n\t\n\t if (request.credentials === 'include') {\n\t xhr.withCredentials = true\n\t }\n\t\n\t if ('responseType' in xhr && support.blob) {\n\t xhr.responseType = 'blob'\n\t }\n\t\n\t request.headers.forEach(function(value, name) {\n\t xhr.setRequestHeader(name, value)\n\t })\n\t\n\t xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)\n\t })\n\t }\n\t self.fetch.polyfill = true\n\t})(typeof self !== 'undefined' ? self : this);\n\n\n/***/ }\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// whatwg-fetch.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 d53b65d3ebbd53c620c1","(function(self) {\n 'use strict';\n\n if (self.fetch) {\n return\n }\n\n var support = {\n searchParams: 'URLSearchParams' in self,\n iterable: 'Symbol' in self && 'iterator' in Symbol,\n blob: 'FileReader' in self && 'Blob' in self && (function() {\n try {\n new Blob()\n return true\n } catch(e) {\n return false\n }\n })(),\n formData: 'FormData' in self,\n arrayBuffer: 'ArrayBuffer' in self\n }\n\n if (support.arrayBuffer) {\n var viewClasses = [\n '[object Int8Array]',\n '[object Uint8Array]',\n '[object Uint8ClampedArray]',\n '[object Int16Array]',\n '[object Uint16Array]',\n '[object Int32Array]',\n '[object Uint32Array]',\n '[object Float32Array]',\n '[object Float64Array]'\n ]\n\n var isDataView = function(obj) {\n return obj && DataView.prototype.isPrototypeOf(obj)\n }\n\n var isArrayBufferView = ArrayBuffer.isView || function(obj) {\n return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1\n }\n }\n\n function normalizeName(name) {\n if (typeof name !== 'string') {\n name = String(name)\n }\n if (/[^a-z0-9\\-#$%&'*+.\\^_`|~]/i.test(name)) {\n throw new TypeError('Invalid character in header field name')\n }\n return name.toLowerCase()\n }\n\n function normalizeValue(value) {\n if (typeof value !== 'string') {\n value = String(value)\n }\n return value\n }\n\n // Build a destructive iterator for the value list\n function iteratorFor(items) {\n var iterator = {\n next: function() {\n var value = items.shift()\n return {done: value === undefined, value: value}\n }\n }\n\n if (support.iterable) {\n iterator[Symbol.iterator] = function() {\n return iterator\n }\n }\n\n return iterator\n }\n\n function Headers(headers) {\n this.map = {}\n\n if (headers instanceof Headers) {\n headers.forEach(function(value, name) {\n this.append(name, value)\n }, this)\n\n } else if (headers) {\n Object.getOwnPropertyNames(headers).forEach(function(name) {\n this.append(name, headers[name])\n }, this)\n }\n }\n\n Headers.prototype.append = function(name, value) {\n name = normalizeName(name)\n value = normalizeValue(value)\n var oldValue = this.map[name]\n this.map[name] = oldValue ? oldValue+','+value : value\n }\n\n Headers.prototype['delete'] = function(name) {\n delete this.map[normalizeName(name)]\n }\n\n Headers.prototype.get = function(name) {\n name = normalizeName(name)\n return this.has(name) ? this.map[name] : null\n }\n\n Headers.prototype.has = function(name) {\n return this.map.hasOwnProperty(normalizeName(name))\n }\n\n Headers.prototype.set = function(name, value) {\n this.map[normalizeName(name)] = normalizeValue(value)\n }\n\n Headers.prototype.forEach = function(callback, thisArg) {\n for (var name in this.map) {\n if (this.map.hasOwnProperty(name)) {\n callback.call(thisArg, this.map[name], name, this)\n }\n }\n }\n\n Headers.prototype.keys = function() {\n var items = []\n this.forEach(function(value, name) { items.push(name) })\n return iteratorFor(items)\n }\n\n Headers.prototype.values = function() {\n var items = []\n this.forEach(function(value) { items.push(value) })\n return iteratorFor(items)\n }\n\n Headers.prototype.entries = function() {\n var items = []\n this.forEach(function(value, name) { items.push([name, value]) })\n return iteratorFor(items)\n }\n\n if (support.iterable) {\n Headers.prototype[Symbol.iterator] = Headers.prototype.entries\n }\n\n function consumed(body) {\n if (body.bodyUsed) {\n return Promise.reject(new TypeError('Already read'))\n }\n body.bodyUsed = true\n }\n\n function fileReaderReady(reader) {\n return new Promise(function(resolve, reject) {\n reader.onload = function() {\n resolve(reader.result)\n }\n reader.onerror = function() {\n reject(reader.error)\n }\n })\n }\n\n function readBlobAsArrayBuffer(blob) {\n var reader = new FileReader()\n var promise = fileReaderReady(reader)\n reader.readAsArrayBuffer(blob)\n return promise\n }\n\n function readBlobAsText(blob) {\n var reader = new FileReader()\n var promise = fileReaderReady(reader)\n reader.readAsText(blob)\n return promise\n }\n\n function readArrayBufferAsText(buf) {\n var view = new Uint8Array(buf)\n var chars = new Array(view.length)\n\n for (var i = 0; i < view.length; i++) {\n chars[i] = String.fromCharCode(view[i])\n }\n return chars.join('')\n }\n\n function bufferClone(buf) {\n if (buf.slice) {\n return buf.slice(0)\n } else {\n var view = new Uint8Array(buf.byteLength)\n view.set(new Uint8Array(buf))\n return view.buffer\n }\n }\n\n function Body() {\n this.bodyUsed = false\n\n this._initBody = function(body) {\n this._bodyInit = body\n if (!body) {\n this._bodyText = ''\n } else if (typeof body === 'string') {\n this._bodyText = body\n } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {\n this._bodyBlob = body\n } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {\n this._bodyFormData = body\n } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n this._bodyText = body.toString()\n } else if (support.arrayBuffer && support.blob && isDataView(body)) {\n this._bodyArrayBuffer = bufferClone(body.buffer)\n // IE 10-11 can't handle a DataView body.\n this._bodyInit = new Blob([this._bodyArrayBuffer])\n } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {\n this._bodyArrayBuffer = bufferClone(body)\n } else {\n throw new Error('unsupported BodyInit type')\n }\n\n if (!this.headers.get('content-type')) {\n if (typeof body === 'string') {\n this.headers.set('content-type', 'text/plain;charset=UTF-8')\n } else if (this._bodyBlob && this._bodyBlob.type) {\n this.headers.set('content-type', this._bodyBlob.type)\n } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {\n this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')\n }\n }\n }\n\n if (support.blob) {\n this.blob = function() {\n var rejected = consumed(this)\n if (rejected) {\n return rejected\n }\n\n if (this._bodyBlob) {\n return Promise.resolve(this._bodyBlob)\n } else if (this._bodyArrayBuffer) {\n return Promise.resolve(new Blob([this._bodyArrayBuffer]))\n } else if (this._bodyFormData) {\n throw new Error('could not read FormData body as blob')\n } else {\n return Promise.resolve(new Blob([this._bodyText]))\n }\n }\n\n this.arrayBuffer = function() {\n if (this._bodyArrayBuffer) {\n return consumed(this) || Promise.resolve(this._bodyArrayBuffer)\n } else {\n return this.blob().then(readBlobAsArrayBuffer)\n }\n }\n }\n\n this.text = function() {\n var rejected = consumed(this)\n if (rejected) {\n return rejected\n }\n\n if (this._bodyBlob) {\n return readBlobAsText(this._bodyBlob)\n } else if (this._bodyArrayBuffer) {\n return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))\n } else if (this._bodyFormData) {\n throw new Error('could not read FormData body as text')\n } else {\n return Promise.resolve(this._bodyText)\n }\n }\n\n if (support.formData) {\n this.formData = function() {\n return this.text().then(decode)\n }\n }\n\n this.json = function() {\n return this.text().then(JSON.parse)\n }\n\n return this\n }\n\n // HTTP methods whose capitalization should be normalized\n var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']\n\n function normalizeMethod(method) {\n var upcased = method.toUpperCase()\n return (methods.indexOf(upcased) > -1) ? upcased : method\n }\n\n function Request(input, options) {\n options = options || {}\n var body = options.body\n\n if (input instanceof Request) {\n if (input.bodyUsed) {\n throw new TypeError('Already read')\n }\n this.url = input.url\n this.credentials = input.credentials\n if (!options.headers) {\n this.headers = new Headers(input.headers)\n }\n this.method = input.method\n this.mode = input.mode\n if (!body && input._bodyInit != null) {\n body = input._bodyInit\n input.bodyUsed = true\n }\n } else {\n this.url = String(input)\n }\n\n this.credentials = options.credentials || this.credentials || 'omit'\n if (options.headers || !this.headers) {\n this.headers = new Headers(options.headers)\n }\n this.method = normalizeMethod(options.method || this.method || 'GET')\n this.mode = options.mode || this.mode || null\n this.referrer = null\n\n if ((this.method === 'GET' || this.method === 'HEAD') && body) {\n throw new TypeError('Body not allowed for GET or HEAD requests')\n }\n this._initBody(body)\n }\n\n Request.prototype.clone = function() {\n return new Request(this, { body: this._bodyInit })\n }\n\n function decode(body) {\n var form = new FormData()\n body.trim().split('&').forEach(function(bytes) {\n if (bytes) {\n var split = bytes.split('=')\n var name = split.shift().replace(/\\+/g, ' ')\n var value = split.join('=').replace(/\\+/g, ' ')\n form.append(decodeURIComponent(name), decodeURIComponent(value))\n }\n })\n return form\n }\n\n function parseHeaders(rawHeaders) {\n var headers = new Headers()\n rawHeaders.split(/\\r?\\n/).forEach(function(line) {\n var parts = line.split(':')\n var key = parts.shift().trim()\n if (key) {\n var value = parts.join(':').trim()\n headers.append(key, value)\n }\n })\n return headers\n }\n\n Body.call(Request.prototype)\n\n function Response(bodyInit, options) {\n if (!options) {\n options = {}\n }\n\n this.type = 'default'\n this.status = 'status' in options ? options.status : 200\n this.ok = this.status >= 200 && this.status < 300\n this.statusText = 'statusText' in options ? options.statusText : 'OK'\n this.headers = new Headers(options.headers)\n this.url = options.url || ''\n this._initBody(bodyInit)\n }\n\n Body.call(Response.prototype)\n\n Response.prototype.clone = function() {\n return new Response(this._bodyInit, {\n status: this.status,\n statusText: this.statusText,\n headers: new Headers(this.headers),\n url: this.url\n })\n }\n\n Response.error = function() {\n var response = new Response(null, {status: 0, statusText: ''})\n response.type = 'error'\n return response\n }\n\n var redirectStatuses = [301, 302, 303, 307, 308]\n\n Response.redirect = function(url, status) {\n if (redirectStatuses.indexOf(status) === -1) {\n throw new RangeError('Invalid status code')\n }\n\n return new Response(null, {status: status, headers: {location: url}})\n }\n\n self.Headers = Headers\n self.Request = Request\n self.Response = Response\n\n self.fetch = function(input, init) {\n return new Promise(function(resolve, reject) {\n var request = new Request(input, init)\n var xhr = new XMLHttpRequest()\n\n xhr.onload = function() {\n var options = {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: parseHeaders(xhr.getAllResponseHeaders() || '')\n }\n options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')\n var body = 'response' in xhr ? xhr.response : xhr.responseText\n resolve(new Response(body, options))\n }\n\n xhr.onerror = function() {\n reject(new TypeError('Network request failed'))\n }\n\n xhr.ontimeout = function() {\n reject(new TypeError('Network request failed'))\n }\n\n xhr.open(request.method, request.url, true)\n\n if (request.credentials === 'include') {\n xhr.withCredentials = true\n }\n\n if ('responseType' in xhr && support.blob) {\n xhr.responseType = 'blob'\n }\n\n request.headers.forEach(function(value, name) {\n xhr.setRequestHeader(name, value)\n })\n\n xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)\n })\n }\n self.fetch.polyfill = true\n})(typeof self !== 'undefined' ? self : this);\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/whatwg-fetch/fetch.js\n// module id = 0\n// module chunks = 1"],"sourceRoot":""} \ No newline at end of file