From 440de558243e5e566fc4b95dfc0acacb583e8790 Mon Sep 17 00:00:00 2001 From: Murod Khaydarov Date: Thu, 9 Nov 2017 20:37:36 +0300 Subject: [PATCH] event dispatchers --- codex-editor.js | 5650 ++---------------- codex-editor.js.map | 2 +- codex.js | 124 +- example.html | 8 +- modules/core.js | 389 -- {modules => src/modules}/anchors.js | 0 {modules => src/modules}/callbacks.js | 0 {modules => src/modules}/caret.js | 0 {modules => src/modules}/content.js | 0 src/modules/core.js | 412 ++ {modules => src/modules}/destroyer.js | 0 {modules => src/modules}/draw.js | 0 {modules => src/modules}/listeners.js | 0 {modules => src/modules}/notifications.js | 0 {modules => src/modules}/parser.js | 0 {modules => src/modules}/paste.js | 0 {modules => src/modules}/renderer.js | 0 {modules => src/modules}/sanitizer.js | 0 {modules => src/modules}/saver.js | 0 {modules => src/modules}/toolbar/inline.js | 0 {modules => src/modules}/toolbar/settings.js | 0 {modules => src/modules}/toolbar/toolbar.js | 0 {modules => src/modules}/toolbar/toolbox.js | 0 {modules => src/modules}/tools.js | 0 {modules => src/modules}/transport.js | 0 {modules => src/modules}/ui.js | 0 26 files changed, 975 insertions(+), 5610 deletions(-) delete mode 100644 modules/core.js rename {modules => src/modules}/anchors.js (100%) rename {modules => src/modules}/callbacks.js (100%) rename {modules => src/modules}/caret.js (100%) rename {modules => src/modules}/content.js (100%) create mode 100644 src/modules/core.js rename {modules => src/modules}/destroyer.js (100%) rename {modules => src/modules}/draw.js (100%) rename {modules => src/modules}/listeners.js (100%) rename {modules => src/modules}/notifications.js (100%) rename {modules => src/modules}/parser.js (100%) rename {modules => src/modules}/paste.js (100%) rename {modules => src/modules}/renderer.js (100%) rename {modules => src/modules}/sanitizer.js (100%) rename {modules => src/modules}/saver.js (100%) rename {modules => src/modules}/toolbar/inline.js (100%) rename {modules => src/modules}/toolbar/settings.js (100%) rename {modules => src/modules}/toolbar/toolbar.js (100%) rename {modules => src/modules}/toolbar/toolbox.js (100%) rename {modules => src/modules}/tools.js (100%) rename {modules => src/modules}/transport.js (100%) rename {modules => src/modules}/ui.js (100%) diff --git a/codex-editor.js b/codex-editor.js index f1552ef3..30e54926 100644 --- a/codex-editor.js +++ b/codex-editor.js @@ -41,8 +41,9 @@ var CodexEditor = /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ -/******/ ([ -/* 0 */ +/******/ ({ + +/***/ 0: /***/ (function(module, exports, __webpack_require__) { 'use strict'; @@ -52,10 +53,12 @@ var CodexEditor = function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** - * * Codex Editor * - * @author Codex Team + * + * + * + * @author CodeX Team */ module.exports = function () { _createClass(CodexEditor, null, [{ @@ -81,7 +84,7 @@ var CodexEditor = * @param config * * @property this.configuration - editor instance configuration - * @property this.instances - editor module instances + * @property this.moduleInstances - editor module instances */ }]); @@ -93,54 +96,96 @@ var CodexEditor = _classCallCheck(this, CodexEditor); this.configuration = config; - this.instances = []; + this.moduleInstances = []; - var modules = ['core', 'tools', 'transport', 'renderer', 'saver', 'content', 'toolbar/toolbar', 'callbacks', 'draw', 'caret', 'notifications', 'parser', 'sanitizer', 'listeners', 'destroyer', 'paste'], - modulePath = './modules/'; + this.eventsDispatcher = new Events(); - this.init(modulePath); + this.init(); } /** * Initializes modules: * First: requiring modules from path * Second: memorizing the instances - * - * @param {String} module name - * @param {String} module path */ _createClass(CodexEditor, [{ key: 'init', - value: function init(path) { + value: function init() { - var core = __webpack_require__(1), - tools = __webpack_require__(2), - transport = __webpack_require__(3), - renderer = __webpack_require__(4), - saver = __webpack_require__(5), - content = __webpack_require__(6), - toolbar = __webpack_require__(7), - callbacks = __webpack_require__(11), - draw = __webpack_require__(12), - caret = __webpack_require__(13), - notifications = __webpack_require__(14), - parser = __webpack_require__(15), - sanitizer = __webpack_require__(16), - listeners = __webpack_require__(18), - destroyer = __webpack_require__(19), - paste = __webpack_require__(20); + var core = __webpack_require__(21); + // tools = require('./src/modules/tools'), + // transport = require('./src/modules/transport'), + // renderer = require('./src/modules/renderer'), + // saver = require('./src/modules/saver'), + // content = require('./src/modules/content'), + // toolbar = require('./src/modules/toolbar/toolbar'), + // callbacks = require('./src/modules/callbacks'), + // draw = require('./src/modules/draw'), + // caret = require('./src/modules/caret'), + // notifications = require('./src/modules/notifications'), + // parser = require('./src/modules/parser'), + // sanitizer = require('./src/modules/sanitizer'), + // listeners = require('./src/modules/listeners'), + // destroyer = require('./src/modules/destroyer'), + // paste = require('./src/modules/paste'); - this.instances['core'] = core; - this.instances['tools'] = tools; - - console.log('Class', this); + this.moduleInstances['core'] = new core({ eventDispatcher: this.eventsDispatcher }); + // this.moduleInstances['tools'] = tools; + // this.moduleInstances['transport'] = transport; + // this.moduleInstances['renderer'] = renderer; + // this.moduleInstances['saver'] = saver; + // this.moduleInstances['content'] = content; + // this.moduleInstances['toolbar'] = toolbar; + // this.moduleInstances['callbacks'] = callbacks; + // this.moduleInstances['draw'] = draw; + // this.moduleInstances['caret'] = caret; + // this.moduleInstances['notifications'] = notifications; + // this.moduleInstances['parser'] = parser; + // this.moduleInstances['sanitizer'] = sanitizer; + // this.moduleInstances['listeners'] = listeners; + // this.moduleInstances['destroyer'] = destroyer; + // this.moduleInstances['paste'] = paste; } }]); return CodexEditor; }(); + + var Events = function () { + function Events() { + _classCallCheck(this, Events); + + this.subscribers = {}; + } + + _createClass(Events, [{ + key: 'on', + value: function on(eventName, callback) { + + if (!(eventName in this.subscribers)) { + + this.subscribers[eventName] = []; + } + + // group by events + this.subscribers[eventName].push(callback); + } + }, { + key: 'emit', + value: function emit(eventName, data) { + + this.subscribers[eventName].reduce(function (previousData, currentHandler) { + + currentHandler(previousData); + return previousData; + }, data); + } + }]); + + return Events; + }(); // module.exports = (function (editor) { // // 'use strict'; @@ -282,12 +327,15 @@ var CodexEditor = // })({}); /***/ }), -/* 1 */ + +/***/ 21: /***/ (function(module, exports) { 'use strict'; - var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Codex Editor Core @@ -296,5148 +344,416 @@ var CodexEditor = * @version 1.1.3 */ - module.exports = function (core) { - - var editor = 1; - - /** - * @public - * - * Editor preparing method - * @return Promise - */ - core.prepare = function (userSettings) { - - return new Promise(function (resolve, reject) { - - if (userSettings) { - - editor.settings.tools = userSettings.tools || editor.settings.tools; - } - - if (userSettings.data) { - - editor.state.blocks = userSettings.data; - } - - if (userSettings.initialBlockPlugin) { - - editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin; - } - - if (userSettings.sanitizer) { - - editor.settings.sanitizer = userSettings.sanitizer; - } - - editor.hideToolbar = userSettings.hideToolbar; - - editor.settings.placeholder = userSettings.placeholder || ''; - - editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId); - - if (_typeof(editor.nodes.holder) === undefined || editor.nodes.holder === null) { - - reject(Error("Holder wasn't found by ID: #" + userSettings.holderId)); - } else { - - resolve(); - } - }); - }; - - /** - * Logging method - * @param type = ['log', 'info', 'warn'] - */ - core.log = function (msg, type, arg) { - - type = type || 'log'; - - if (!arg) { - - arg = msg || 'undefined'; - msg = '[codex-editor]: %o'; - } else { - - msg = '[codex-editor]: ' + msg; - } - - try { - - if ('console' in window && window.console[type]) { - - if (arg) window.console[type](msg, arg);else window.console[type](msg); - } - } catch (e) {} - }; - - /** - * @protected - * - * Helper for insert one element after another - */ - core.insertAfter = function (target, element) { - - target.parentNode.insertBefore(element, target.nextSibling); - }; - - /** - * @const - * - * Readable DOM-node types map - */ - core.nodeTypes = { - TAG: 1, - TEXT: 3, - COMMENT: 8, - DOCUMENT_FRAGMENT: 11 - }; - - /** - * @const - * Readable keys map - */ - 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 }; - - /** - * @protected - * - * Check object for DOM node - */ - core.isDomNode = function (el) { - - return el && (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG; - }; - - /** - * Checks passed object for emptiness - * @require ES5 - Object.keys - * @param {object} - */ - core.isEmpty = function (obj) { - - return Object.keys(obj).length === 0; - }; - - /** - * Native Ajax - * @param {String} settings.url - request URL - * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks - * @param {function} settings.success - * @param {function} settings.progress - */ - core.ajax = function (settings) { - - if (!settings || !settings.url) { - - return; - } - - var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'), - encodedString, - isFormData, - prop; - - settings.async = true; - settings.type = settings.type || 'GET'; - settings.data = settings.data || ''; - settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8'; - - if (settings.type == 'GET' && settings.data) { - - settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data; - } else { - - encodedString = ''; - for (prop in settings.data) { - - encodedString += prop + '=' + encodeURIComponent(settings.data[prop]) + '&'; - } - } - - if (settings.withCredentials) { - - XMLHTTP.withCredentials = true; - } - - /** - * Value returned in beforeSend funtion will be passed as context to the other response callbacks - * If beforeSend returns false, AJAX will be blocked - */ - var responseContext = void 0, - beforeSendResult = void 0; - - if (typeof settings.beforeSend === 'function') { - - beforeSendResult = settings.beforeSend.call(); - - if (beforeSendResult === false) { - - return; - } - } - - XMLHTTP.open(settings.type, settings.url, settings.async); - - /** - * If we send FormData, we need no content-type header - */ - isFormData = isFormData_(settings.data); - - if (!isFormData) { - - if (settings.type !== 'POST') { - - XMLHTTP.setRequestHeader('Content-type', settings['content-type']); - } else { - - XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - } - } - - XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - - responseContext = beforeSendResult || XMLHTTP; - - if (typeof settings.progress === 'function') { - - XMLHTTP.upload.onprogress = settings.progress.bind(responseContext); - } - - XMLHTTP.onreadystatechange = function () { - - if (XMLHTTP.readyState === 4) { - - if (XMLHTTP.status === 200) { - - if (typeof settings.success === 'function') { - - settings.success.call(responseContext, XMLHTTP.responseText); - } - } else { - - if (typeof settings.error === 'function') { - - settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status); - } - } - } - }; - - if (isFormData) { - - // Sending FormData - XMLHTTP.send(settings.data); - } else { - - // POST requests - XMLHTTP.send(encodedString); - } - - return XMLHTTP; - }; - - /** - * Appends script to head of document - * @return Promise - */ - core.importScript = function (scriptPath, instanceName) { - - return new Promise(function (resolve, reject) { - - var script = void 0; - - /** Script is already loaded */ - if (!instanceName) { - - reject('Instance name is missed'); - } else if (document.getElementById(editor.scriptPrefix + instanceName)) { - - resolve(scriptPath); - } - - script = document.createElement('SCRIPT'); - script.async = true; - script.defer = true; - script.id = editor.scriptPrefix + instanceName; - - script.onload = function () { - - resolve(scriptPath); - }; - - script.onerror = function () { - - reject(scriptPath); - }; - - script.src = scriptPath; - document.head.appendChild(script); - }); - }; - - /** - * Function for checking is it FormData object to send. - * @param {Object} object to check - * @return boolean - */ - var isFormData_ = function isFormData_(object) { - - return object instanceof FormData; - }; - - /** - * Check block - * @param target - * @description Checks target is it native input - */ - core.isNativeInput = function (target) { - - var nativeInputAreas = ['INPUT', 'TEXTAREA']; - - return nativeInputAreas.indexOf(target.tagName) != -1; - }; - - /** - * Check if block is empty - * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME - * - * @param block - * @returns {boolean} - */ - core.isBlockEmpty = function (block) { - - var EXCEPTION_TAGS = ['IMG', 'IFRAME']; - - var nativeInputs = block.querySelectorAll('textarea, input'), - nativeInputsAreEmpty = true, - textContentIsEmpty = !block.textContent.trim(); - - Array.prototype.forEach.call(nativeInputs, function (input) { - - if (input.type == 'textarea' || input.type == 'text') { - - nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim(); - } - }); - - return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName); - }; - - return core; - }({}); - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Module working with plugins - */ module.exports = function () { + function Core(_ref) { + var eventDispatcher = _ref.eventDispatcher; - var editor = codex.editor; + _classCallCheck(this, Core); - /** - * Initialize plugins before using - * Ex. Load scripts or call some internal methods - * @return Promise - */ - function prepare() { + this.eventDispatcher = eventDispatcher; + this.data = [1, 2, 3]; + this.init(); + } - return new Promise(function (resolve_, reject_) { + _createClass(Core, [{ + key: 'init', + value: function init() { - Promise.resolve() + this.eventDispatcher.on('Editor proccessing...', function (data) { - /** - * Compose a sequence of plugins that requires preparation - */ - .then(function () { - - var pluginsRequiresPreparation = [], - allPlugins = editor.tools; - - for (var pluginName in allPlugins) { - - var plugin = allPlugins[pluginName]; - - if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) { - - continue; - } - - pluginsRequiresPreparation.push(plugin); - } - - /** - * If no one passed plugins requires preparation, finish prepare() and go ahead - */ - if (!pluginsRequiresPreparation.length) { - - resolve_(); - } - - return pluginsRequiresPreparation; - }) - - /** Wait plugins while they prepares */ - .then(waitAllPluginsPreparation_).then(function () { - - editor.core.log('Plugins loaded', 'info'); - resolve_(); - }).catch(function (error) { - - reject_(error); + console.log('Function fired when editor started proccess'); }); - }); - } - /** - * @param {array} plugins - list of tools that requires preparation - * @return {Promise} resolved while all plugins will be ready or failed - */ - function waitAllPluginsPreparation_(plugins) { + this.eventDispatcher.emit('Editor proccessing...', this.data); + } + }]); - /** - * @calls allPluginsProcessed__ when all plugins prepared or failed - */ - return new Promise(function (allPluginsProcessed__) { - - /** - * pluck each element from queue - * First, send resolved Promise as previous value - * Each plugins "prepare" method returns a Promise, that's why - * reduce current element will not be able to continue while can't get - * a resolved Promise - * - * If last plugin is "prepared" then go to the next stage of initialization - */ - plugins.reduce(function (previousValue, plugin, iteration) { - - return previousValue.then(function () { - - /** - * Wait till plugins prepared - * @calls pluginIsReady__ when plugin is ready or failed - */ - return new Promise(function (pluginIsReady__) { - - callPluginsPrepareMethod_(plugin).then(pluginIsReady__).then(function () { - - plugin.available = true; - }).catch(function (error) { - - editor.core.log('Plugin \xAB' + plugin.type + '\xBB was not loaded. Preparation failed because %o', 'warn', error); - plugin.available = false; - plugin.loadingMessage = error; - - /** Go ahead even some plugin has problems */ - pluginIsReady__(); - }).then(function () { - - /** If last plugin has problems then just ignore and continue */ - if (iteration == plugins.length - 1) { - - allPluginsProcessed__(); - } - }); - }); - }); - }, Promise.resolve()); - }); - } - - var callPluginsPrepareMethod_ = function callPluginsPrepareMethod_(plugin) { - - return plugin.prepare(plugin.config || {}); - }; - - return { - prepare: prepare - }; + return Core; }(); - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * - * Codex.Editor Transport Module - * - * @copyright 2017 Codex-Team - * @version 1.2.0 - */ - - module.exports = function (transport) { - - var editor = codex.editor; - - /** - * @private {Object} current XmlHttpRequest instance - */ - var currentRequest = null; - - /** - * @type {null} | {DOMElement} input - keeps input element in memory - */ - transport.input = null; - - /** - * @property {Object} arguments - keep plugin settings and defined callbacks - */ - transport.arguments = null; - - /** - * Prepares input element where will be files - */ - transport.prepare = function () { - - var input = editor.draw.node('INPUT', '', { type: 'file' }); - - editor.listeners.add(input, 'change', editor.transport.fileSelected); - editor.transport.input = input; - }; - - /** Clear input when files is uploaded */ - transport.clearInput = function () { - - /** Remove old input */ - transport.input = null; - - /** Prepare new one */ - transport.prepare(); - }; - - /** - * Callback for file selection - * @param {Event} event - */ - transport.fileSelected = function () { - - var input = this, - i, - files = input.files, - formData = new FormData(); - - if (editor.transport.arguments.multiple === true) { - - for (i = 0; i < files.length; i++) { - - formData.append('files[]', files[i], files[i].name); - } - } else { - - formData.append('files', files[0], files[0].name); - } - - currentRequest = editor.core.ajax({ - type: 'POST', - data: formData, - url: editor.transport.arguments.url, - beforeSend: editor.transport.arguments.beforeSend, - success: editor.transport.arguments.success, - error: editor.transport.arguments.error, - progress: editor.transport.arguments.progress - }); - - /** Clear input */ - transport.clearInput(); - }; - - /** - * Use plugin callbacks - * @protected - * - * @param {Object} args - can have : - * @param {String} args.url - fetch URL - * @param {Function} args.beforeSend - function calls before sending ajax - * @param {Function} args.success - success callback - * @param {Function} args.error - on error handler - * @param {Function} args.progress - xhr onprogress handler - * @param {Boolean} args.multiple - allow select several files - * @param {String} args.accept - adds accept attribute - */ - transport.selectAndUpload = function (args) { - - transport.arguments = args; - - if (args.multiple === true) { - - transport.input.setAttribute('multiple', 'multiple'); - } - - if (args.accept) { - - transport.input.setAttribute('accept', args.accept); - } - - transport.input.click(); - }; - - transport.abort = function () { - - currentRequest.abort(); - - currentRequest = null; - }; - - return transport; - }({}); - -/***/ }), -/* 4 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor Renderer Module - * - * @author Codex Team - * @version 1.0 - */ - - module.exports = function (renderer) { - - var editor = codex.editor; - - /** - * Asyncronously parses input JSON to redactor blocks - */ - renderer.makeBlocksFromData = function () { - - /** - * If redactor is empty, add first paragraph to start writing - */ - if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) { - - editor.ui.addInitialBlock(); - return; - } - - Promise.resolve() - - /** First, get JSON from state */ - .then(function () { - - return editor.state.blocks; - }) - - /** Then, start to iterate they */ - .then(editor.renderer.appendBlocks) - - /** Write log if something goes wrong */ - .catch(function (error) { - - editor.core.log('Error while parsing JSON: %o', 'error', error); - }); - }; - - /** - * Parses JSON to blocks - * @param {object} data - * @return Primise -> nodeList - */ - renderer.appendBlocks = function (data) { - - var blocks = data.items; - - /** - * Sequence of one-by-one blocks appending - * Uses to save blocks order after async-handler - */ - var nodeSequence = Promise.resolve(); - - for (var index = 0; index < blocks.length; index++) { - - /** Add node to sequence at specified index */ - editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index); - } - }; - - /** - * Append node at specified index - */ - renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) { - - /** We need to append node to sequence */ - nodeSequence - - /** first, get node async-aware */ - .then(function () { - - return editor.renderer.getNodeAsync(blocks, index); - }) - - /** - * second, compose editor-block from JSON object - */ - .then(editor.renderer.createBlockFromData) - - /** - * now insert block to redactor - */ - .then(function (blockData) { - - /** - * blockData has 'block', 'type' and 'stretched' information - */ - editor.content.insertBlock(blockData); - - /** Pass created block to next step */ - return blockData.block; - }) - - /** Log if something wrong with node */ - .catch(function (error) { - - editor.core.log('Node skipped while parsing because %o', 'error', error); - }); - }; - - /** - * Asynchronously returns block data from blocksList by index - * @return Promise to node - */ - renderer.getNodeAsync = function (blocksList, index) { - - return Promise.resolve().then(function () { - - return { - tool: blocksList[index], - position: index - }; - }); - }; - - /** - * Creates editor block by JSON-data - * - * @uses render method of each plugin - * - * @param {Object} toolData.tool - * { header : { - * text: '', - * type: 'H3', ... - * } - * } - * @param {Number} toolData.position - index in input-blocks array - * @return {Object} with type and Element - */ - renderer.createBlockFromData = function (toolData) { - - /** New parser */ - var block, - tool = toolData.tool, - pluginName = tool.type; - - /** Get first key of object that stores plugin name */ - // for (var pluginName in blockData) break; - - /** Check for plugin existance */ - if (!editor.tools[pluginName]) { - - throw Error('Plugin \xAB' + pluginName + '\xBB not found'); - } - - /** Check for plugin having render method */ - if (typeof editor.tools[pluginName].render != 'function') { - - throw Error('Plugin \xAB' + pluginName + '\xBB must have \xABrender\xBB method'); - } - - if (editor.tools[pluginName].available === false) { - - block = editor.draw.unavailableBlock(); - - block.innerHTML = editor.tools[pluginName].loadingMessage; - - /** - * Saver will extract data from initial block data by position in array - */ - block.dataset.inputPosition = toolData.position; - } else { - - /** New Parser */ - block = editor.tools[pluginName].render(tool.data); - } - - /** is first-level block stretched */ - var stretched = editor.tools[pluginName].isStretched || false; - - /** Retrun type and block */ - return { - type: pluginName, - block: block, - stretched: stretched - }; - }; - - return renderer; - }({}); - -/***/ }), -/* 5 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor Saver - * - * @author Codex Team - * @version 1.1.0 - */ - - module.exports = function (saver) { - - var editor = codex.editor; - - /** - * @public - * Save blocks - */ - saver.save = function () { - - /** Save html content of redactor to memory */ - editor.state.html = editor.nodes.redactor.innerHTML; - - /** Clean jsonOutput state */ - editor.state.jsonOutput = []; - - return saveBlocks(editor.nodes.redactor.childNodes); - }; - - /** - * @private - * Save each block data - * - * @param blocks - * @returns {Promise.} - */ - var saveBlocks = function saveBlocks(blocks) { - - var data = []; - - for (var index = 0; index < blocks.length; index++) { - - data.push(getBlockData(blocks[index])); - } - - return Promise.all(data).then(makeOutput).catch(editor.core.log); - }; - - /** Save and validate block data */ - var getBlockData = function getBlockData(block) { - - return saveBlockData(block).then(validateBlockData).catch(editor.core.log); - }; - - /** - * @private - * Call block`s plugin save method and return saved data - * - * @param block - * @returns {Object} - */ - var saveBlockData = function saveBlockData(block) { - - var pluginName = block.dataset.tool; - - /** Check for plugin existence */ - if (!editor.tools[pluginName]) { - - editor.core.log('Plugin \xAB' + pluginName + '\xBB not found', 'error'); - return { data: null, pluginName: null }; - } - - /** Check for plugin having save method */ - if (typeof editor.tools[pluginName].save !== 'function') { - - editor.core.log('Plugin \xAB' + pluginName + '\xBB must have save method', 'error'); - return { data: null, pluginName: null }; - } - - /** Result saver */ - var blockContent = block.childNodes[0], - pluginsContent = blockContent.childNodes[0], - position = pluginsContent.dataset.inputPosition; - - /** If plugin wasn't available then return data from cache */ - if (editor.tools[pluginName].available === false) { - - return Promise.resolve({ data: codex.editor.state.blocks.items[position].data, pluginName: pluginName }); - } - - return Promise.resolve(pluginsContent).then(editor.tools[pluginName].save).then(function (data) { - return Object({ data: data, pluginName: pluginName }); - }); - }; - - /** - * Call plugin`s validate method. Return false if validation failed - * - * @param data - * @param pluginName - * @returns {Object|Boolean} - */ - var validateBlockData = function validateBlockData(_ref) { - var data = _ref.data, - pluginName = _ref.pluginName; - - - if (!data || !pluginName) { - - return false; - } - - if (editor.tools[pluginName].validate) { - - var result = editor.tools[pluginName].validate(data); - - /** - * Do not allow invalid data - */ - if (!result) { - - return false; - } - } - - return { data: data, pluginName: pluginName }; - }; - - /** - * Compile article output - * - * @param savedData - * @returns {{time: number, version, items: (*|Array)}} - */ - var makeOutput = function makeOutput(savedData) { - - savedData = savedData.filter(function (blockData) { - return blockData; - }); - - var items = savedData.map(function (blockData) { - return Object({ type: blockData.pluginName, data: blockData.data }); - }); - - editor.state.jsonOutput = items; - - return { - id: editor.state.blocks.id || null, - time: +new Date(), - version: editor.version, - items: items - }; - }; - - return saver; - }({}); - -/***/ }), -/* 6 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor Content Module - * Works with DOM - * - * @module Codex Editor content module - * - * @author Codex Team - * @version 1.3.13 - * - * @description Module works with Elements that have been appended to the main DOM - */ - - module.exports = function (content) { - - var editor = codex.editor; - - /** - * Links to current active block - * @type {null | Element} - */ - content.currentNode = null; - - /** - * clicked in redactor area - * @type {null | Boolean} - */ - content.editorAreaHightlighted = null; - - /** - * @deprecated - * Synchronizes redactor with original textarea - */ - content.sync = function () { - - editor.core.log('syncing...'); - - /** - * Save redactor content to editor.state - */ - editor.state.html = editor.nodes.redactor.innerHTML; - }; - - /** - * Appends background to the block - * - * @description add CSS class to highlight visually first-level block area - */ - content.markBlock = function () { - - editor.content.currentNode.classList.add(editor.ui.className.BLOCK_HIGHLIGHTED); - }; - - /** - * Clear background - * - * @description clears styles that highlights block - */ - content.clearMark = function () { - - if (editor.content.currentNode) { - - editor.content.currentNode.classList.remove(editor.ui.className.BLOCK_HIGHLIGHTED); - } - }; - - /** - * Finds first-level block - * - * @param {Element} node - selected or clicked in redactors area node - * @protected - * - * @description looks for first-level block. - * gets parent while node is not first-level - */ - content.getFirstLevelBlock = function (node) { - - if (!editor.core.isDomNode(node)) { - - node = node.parentNode; - } - - if (node === editor.nodes.redactor || node === document.body) { - - return null; - } else { - - while (!node.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) { - - node = node.parentNode; - } - - return node; - } - }; - - /** - * Trigger this event when working node changed - * @param {Element} targetNode - first-level of this node will be current - * @protected - * - * @description If targetNode is first-level then we set it as current else we look for parents to find first-level - */ - content.workingNodeChanged = function (targetNode) { - - /** Clear background from previous marked block before we change */ - editor.content.clearMark(); - - if (!targetNode) { - - return; - } - - content.currentNode = content.getFirstLevelBlock(targetNode); - }; - - /** - * Replaces one redactor block with another - * @protected - * @param {Element} targetBlock - block to replace. Mostly currentNode. - * @param {Element} newBlock - * @param {string} newBlockType - type of new block; we need to store it to data-attribute - * - * [!] Function does not saves old block content. - * You can get it manually and pass with newBlock.innerHTML - */ - content.replaceBlock = function (targetBlock, newBlock) { - - if (!targetBlock || !newBlock) { - - editor.core.log('replaceBlock: missed params'); - return; - } - - /** If target-block is not a frist-level block, then we iterate parents to find it */ - while (!targetBlock.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) { - - targetBlock = targetBlock.parentNode; - } - - /** Replacing */ - editor.nodes.redactor.replaceChild(newBlock, targetBlock); - - /** - * Set new node as current - */ - editor.content.workingNodeChanged(newBlock); - - /** - * Add block handlers - */ - editor.ui.addBlockHandlers(newBlock); - - /** - * Save changes - */ - editor.ui.saveInputs(); - }; - - /** - * @protected - * - * Inserts new block to redactor - * Wrapps block into a DIV with BLOCK_CLASSNAME class - * - * @param blockData {object} - * @param blockData.block {Element} element with block content - * @param blockData.type {string} block plugin - * @param needPlaceCaret {bool} pass true to set caret in new block - * - */ - content.insertBlock = function (blockData, needPlaceCaret) { - - var workingBlock = editor.content.currentNode, - newBlockContent = blockData.block, - blockType = blockData.type, - isStretched = blockData.stretched; - - var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched); - - if (workingBlock) { - - editor.core.insertAfter(workingBlock, newBlock); - } else { - - /** - * If redactor is empty, append as first child - */ - editor.nodes.redactor.appendChild(newBlock); - } - - /** - * Block handler - */ - editor.ui.addBlockHandlers(newBlock); - - /** - * Set new node as current - */ - editor.content.workingNodeChanged(newBlock); - - /** - * Save changes - */ - editor.ui.saveInputs(); - - if (needPlaceCaret) { - - /** - * If we don't know input index then we set default value -1 - */ - var currentInputIndex = editor.caret.getCurrentInputIndex() || -1; - - if (currentInputIndex == -1) { - - var editableElement = newBlock.querySelector('[contenteditable]'), - emptyText = document.createTextNode(''); - - editableElement.appendChild(emptyText); - editor.caret.set(editableElement, 0, 0); - - editor.toolbar.move(); - editor.toolbar.showPlusButton(); - } else { - - if (currentInputIndex === editor.state.inputs.length - 1) return; - - /** Timeout for browsers execution */ - window.setTimeout(function () { - - /** Setting to the new input */ - editor.caret.setToNextBlock(currentInputIndex); - editor.toolbar.move(); - editor.toolbar.open(); - }, 10); - } - } - - /** - * Block is inserted, wait for new click that defined focusing on editors area - * @type {boolean} - */ - content.editorAreaHightlighted = false; - }; - - /** - * Replaces blocks with saving content - * @protected - * @param {Element} noteToReplace - * @param {Element} newNode - * @param {Element} blockType - */ - content.switchBlock = function (blockToReplace, newBlock, tool) { - - tool = tool || editor.content.currentNode.dataset.tool; - var newBlockComposed = composeNewBlock_(newBlock, tool); - - /** Replacing */ - editor.content.replaceBlock(blockToReplace, newBlockComposed); - - /** Save new Inputs when block is changed */ - editor.ui.saveInputs(); - }; - - /** - * Iterates between child noted and looking for #text node on deepest level - * @protected - * - * @param {Element} block - node where find - * @param {int} postiton - starting postion - * Example: childNodex.length to find from the end - * or 0 to find from the start - * @return {Text} block - * @uses DFS - */ - content.getDeepestTextNodeFromPosition = function (block, position) { - - /** - * Clear Block from empty and useless spaces with trim. - * Such nodes we should remove - */ - var blockChilds = block.childNodes, - index, - node, - text; - - for (index = 0; index < blockChilds.length; index++) { - - node = blockChilds[index]; - - if (node.nodeType == editor.core.nodeTypes.TEXT) { - - text = node.textContent.trim(); - - /** Text is empty. We should remove this child from node before we start DFS - * decrease the quantity of childs. - */ - if (text === '') { - - block.removeChild(node); - position--; - } - } - } - - if (block.childNodes.length === 0) { - - return document.createTextNode(''); - } - - /** Setting default position when we deleted all empty nodes */ - if (position < 0) position = 1; - - var lookingFromStart = false; - - /** For looking from START */ - if (position === 0) { - - lookingFromStart = true; - position = 1; - } - - while (position) { - - /** initial verticle of node. */ - if (lookingFromStart) { - - block = block.childNodes[0]; - } else { - - block = block.childNodes[position - 1]; - } - - if (block.nodeType == editor.core.nodeTypes.TAG) { - - position = block.childNodes.length; - } else if (block.nodeType == editor.core.nodeTypes.TEXT) { - - position = 0; - } - } - - return block; - }; - - /** - * @private - * @param {Element} block - current plugins render - * @param {String} tool - plugins name - * @param {Boolean} isStretched - make stretched block or not - * - * @description adds necessary information to wrap new created block by first-level holder - */ - var composeNewBlock_ = function composeNewBlock_(block, tool, isStretched) { - - var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}), - blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {}); - - blockContent.appendChild(block); - newBlock.appendChild(blockContent); - - if (isStretched) { - - blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED); - } - - newBlock.dataset.tool = tool; - return newBlock; - }; - - /** - * Returns Range object of current selection - * @protected - */ - content.getRange = function () { - - var selection = window.getSelection().getRangeAt(0); - - return selection; - }; - - /** - * Divides block in two blocks (after and before caret) - * - * @protected - * @param {int} inputIndex - target input index - * - * @description splits current input content to the separate blocks - * When enter is pressed among the words, that text will be splited. - */ - content.splitBlock = function (inputIndex) { - - var selection = window.getSelection(), - anchorNode = selection.anchorNode, - anchorNodeText = anchorNode.textContent, - caretOffset = selection.anchorOffset, - textBeforeCaret, - textNodeBeforeCaret, - textAfterCaret, - textNodeAfterCaret; - - var currentBlock = editor.content.currentNode.querySelector('[contentEditable]'); - - textBeforeCaret = anchorNodeText.substring(0, caretOffset); - textAfterCaret = anchorNodeText.substring(caretOffset); - - textNodeBeforeCaret = document.createTextNode(textBeforeCaret); - - if (textAfterCaret) { - - textNodeAfterCaret = document.createTextNode(textAfterCaret); - } - - var previousChilds = [], - nextChilds = [], - reachedCurrent = false; - - if (textNodeAfterCaret) { - - nextChilds.push(textNodeAfterCaret); - } - - for (var i = 0, child; !!(child = currentBlock.childNodes[i]); i++) { - - if (child != anchorNode) { - - if (!reachedCurrent) { - - previousChilds.push(child); - } else { - - nextChilds.push(child); - } - } else { - - reachedCurrent = true; - } - } - - /** Clear current input */ - editor.state.inputs[inputIndex].innerHTML = ''; - - /** - * Append all childs founded before anchorNode - */ - var previousChildsLength = previousChilds.length; - - for (i = 0; i < previousChildsLength; i++) { - - editor.state.inputs[inputIndex].appendChild(previousChilds[i]); - } - - editor.state.inputs[inputIndex].appendChild(textNodeBeforeCaret); - - /** - * Append text node which is after caret - */ - var nextChildsLength = nextChilds.length, - newNode = document.createElement('div'); - - for (i = 0; i < nextChildsLength; i++) { - - newNode.appendChild(nextChilds[i]); - } - - newNode = newNode.innerHTML; - - /** This type of block creates when enter is pressed */ - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - - /** - * Make new paragraph with text after caret - */ - editor.content.insertBlock({ - type: NEW_BLOCK_TYPE, - block: editor.tools[NEW_BLOCK_TYPE].render({ - text: newNode - }) - }, true); - }; - - /** - * Merges two blocks — current and target - * If target index is not exist, then previous will be as target - * - * @protected - * @param {int} currentInputIndex - * @param {int} targetInputIndex - * - * @description gets two inputs indexes and merges into one - */ - content.mergeBlocks = function (currentInputIndex, targetInputIndex) { - - /** If current input index is zero, then prevent method execution */ - if (currentInputIndex === 0) { - - return; - } - - var targetInput, - currentInputContent = editor.state.inputs[currentInputIndex].innerHTML; - - if (!targetInputIndex) { - - targetInput = editor.state.inputs[currentInputIndex - 1]; - } else { - - targetInput = editor.state.inputs[targetInputIndex]; - } - - targetInput.innerHTML += currentInputContent; - }; - - /** - * Iterates all right siblings and parents, which has right siblings - * while it does not reached the first-level block - * - * @param {Element} node - * @return {boolean} - */ - content.isLastNode = function (node) { - - // console.log('погнали перебор родителей'); - - var allChecked = false; - - while (!allChecked) { - - // console.log('Смотрим на %o', node); - // console.log('Проверим, пустые ли соседи справа'); - - if (!allSiblingsEmpty_(node)) { - - // console.log('Есть непустые соседи. Узел не последний. Выходим.'); - return false; - } - - node = node.parentNode; - - /** - * Проверяем родителей до тех пор, пока не найдем блок первого уровня - */ - if (node.classList.contains(editor.ui.className.BLOCK_CONTENT)) { - - allChecked = true; - } - } - - return true; - }; - - /** - * Checks if all element right siblings is empty - * @param node - */ - var allSiblingsEmpty_ = function allSiblingsEmpty_(node) { - - /** - * Нужно убедиться, что после пустого соседа ничего нет - */ - var sibling = node.nextSibling; - - while (sibling) { - - if (sibling.textContent.length) { - - return false; - } - - sibling = sibling.nextSibling; - } - - return true; - }; - - /** - * @public - * - * @param {string} htmlData - html content as string - * @param {string} plainData - plain text - * @return {string} - html content as string - */ - content.wrapTextWithParagraphs = function (htmlData, plainData) { - - if (!htmlData.trim()) { - - return wrapPlainTextWithParagraphs(plainData); - } - - var wrapper = document.createElement('DIV'), - newWrapper = document.createElement('DIV'), - i, - paragraph, - firstLevelBlocks = ['DIV', 'P'], - blockTyped, - node; - - /** - * Make HTML Element to Wrap Text - * It allows us to work with input data as HTML content - */ - wrapper.innerHTML = htmlData; - paragraph = document.createElement('P'); - - for (i = 0; i < wrapper.childNodes.length; i++) { - - node = wrapper.childNodes[i]; - - blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1; - - /** - * If node is first-levet - * we add this node to our new wrapper - */ - if (blockTyped) { - - /** - * If we had splitted inline nodes to paragraph before - */ - if (paragraph.childNodes.length) { - - newWrapper.appendChild(paragraph.cloneNode(true)); - - /** empty paragraph */ - paragraph = null; - paragraph = document.createElement('P'); - } - - newWrapper.appendChild(node.cloneNode(true)); - } else { - - /** Collect all inline nodes to one as paragraph */ - paragraph.appendChild(node.cloneNode(true)); - - /** if node is last we should append this node to paragraph and paragraph to new wrapper */ - if (i == wrapper.childNodes.length - 1) { - - newWrapper.appendChild(paragraph.cloneNode(true)); - } - } - } - - return newWrapper.innerHTML; - }; - - /** - * Splits strings on new line and wraps paragraphs with

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

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

') + '

'; - }; - - /** - * Finds closest Contenteditable parent from Element - * @param {Element} node element looking from - * @return {Element} node contenteditable - */ - content.getEditableParent = function (node) { - - while (node && node.contentEditable != 'true') { - - node = node.parentNode; - } - - return node; - }; - - /** - * Clear editors content - * - * @param {Boolean} all — if true, delete all article data (content, id, etc.) - */ - content.clear = function (all) { - - editor.nodes.redactor.innerHTML = ''; - editor.content.sync(); - editor.ui.saveInputs(); - if (all) { - - editor.state.blocks = {}; - } else if (editor.state.blocks) { - - editor.state.blocks.items = []; - } - - editor.content.currentNode = null; - }; - - /** - * - * Load new data to editor - * If editor is not empty, just append articleData.items - * - * @param articleData.items - */ - content.load = function (articleData) { - - var currentContent = Object.assign({}, editor.state.blocks); - - editor.content.clear(); - - if (!Object.keys(currentContent).length) { - - editor.state.blocks = articleData; - } else if (!currentContent.items) { - - currentContent.items = articleData.items; - editor.state.blocks = currentContent; - } else { - - currentContent.items = currentContent.items.concat(articleData.items); - editor.state.blocks = currentContent; - } - - editor.renderer.makeBlocksFromData(); - }; - - return content; - }({}); - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - /** - * Codex Editor toolbar module - * - * Contains: - * - Inline toolbox - * - Toolbox within plus button - * - Settings section - * - * @author Codex Team - * @version 1.0 - */ - - module.exports = function (toolbar) { - - var editor = codex.editor; - - toolbar.settings = __webpack_require__(8); - toolbar.inline = __webpack_require__(9); - toolbar.toolbox = __webpack_require__(10); - - /** - * Margin between focused node and toolbar - */ - toolbar.defaultToolbarHeight = 49; - - toolbar.defaultOffset = 34; - - toolbar.opened = false; - - toolbar.current = null; - - /** - * @protected - */ - toolbar.open = function () { - - if (editor.hideToolbar) { - - return; - } - - var toolType = editor.content.currentNode.dataset.tool; - - if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings) { - - editor.nodes.showSettingsButton.classList.add('hide'); - } else { - - editor.nodes.showSettingsButton.classList.remove('hide'); - } - - editor.nodes.toolbar.classList.add('opened'); - this.opened = true; - }; - - /** - * @protected - */ - toolbar.close = function () { - - editor.nodes.toolbar.classList.remove('opened'); - - toolbar.opened = false; - toolbar.current = null; - - for (var button in editor.nodes.toolbarButtons) { - - editor.nodes.toolbarButtons[button].classList.remove('selected'); - } - - /** Close toolbox when toolbar is not displayed */ - editor.toolbar.toolbox.close(); - editor.toolbar.settings.close(); - }; - - toolbar.toggle = function () { - - if (!this.opened) { - - this.open(); - } else { - - this.close(); - } - }; - - toolbar.hidePlusButton = function () { - - editor.nodes.plusButton.classList.add('hide'); - }; - - toolbar.showPlusButton = function () { - - editor.nodes.plusButton.classList.remove('hide'); - }; - - /** - * Moving toolbar to the specified node - */ - toolbar.move = function () { - - /** Close Toolbox when we move toolbar */ - editor.toolbar.toolbox.close(); - - if (!editor.content.currentNode) { - - return; - } - - var newYCoordinate = editor.content.currentNode.offsetTop - editor.toolbar.defaultToolbarHeight / 2 + editor.toolbar.defaultOffset; - - editor.nodes.toolbar.style.transform = 'translate3D(0, ' + Math.floor(newYCoordinate) + 'px, 0)'; - - /** Close trash actions */ - editor.toolbar.settings.hideRemoveActions(); - }; - - return toolbar; - }({}); - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Toolbar settings - * - * @version 1.0.5 - */ - - module.exports = function (settings) { - - var editor = codex.editor; - - settings.opened = false; - - settings.setting = null; - settings.actions = null; - - /** - * Append and open settings - */ - settings.open = function (toolType) { - - /** - * Append settings content - * It's stored in tool.settings - */ - if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings) { - - return; - } - - /** - * Draw settings block - */ - var settingsBlock = editor.tools[toolType].makeSettings(); - - editor.nodes.pluginSettings.appendChild(settingsBlock); - - /** Open settings block */ - editor.nodes.blockSettings.classList.add('opened'); - this.opened = true; - }; - - /** - * Close and clear settings - */ - settings.close = function () { - - editor.nodes.blockSettings.classList.remove('opened'); - editor.nodes.pluginSettings.innerHTML = ''; - - this.opened = false; - }; - - /** - * @param {string} toolType - plugin type - */ - settings.toggle = function (toolType) { - - if (!this.opened) { - - this.open(toolType); - } else { - - this.close(); - } - }; - - /** - * Here we will draw buttons and add listeners to components - */ - settings.makeRemoveBlockButton = function () { - - var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}), - settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML: '' }), - actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}), - confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent: 'Удалить блок' }), - cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent: 'Отмена' }); - - editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false); - - editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false); - - editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false); - - actionWrapper.appendChild(confirmAction); - actionWrapper.appendChild(cancelAction); - - removeBlockWrapper.appendChild(settingButton); - removeBlockWrapper.appendChild(actionWrapper); - - /** Save setting */ - editor.toolbar.settings.setting = settingButton; - editor.toolbar.settings.actions = actionWrapper; - - return removeBlockWrapper; - }; - - settings.removeButtonClicked = function () { - - var action = editor.toolbar.settings.actions; - - if (action.classList.contains('opened')) { - - editor.toolbar.settings.hideRemoveActions(); - } else { - - editor.toolbar.settings.showRemoveActions(); - } - - editor.toolbar.toolbox.close(); - editor.toolbar.settings.close(); - }; - - settings.cancelRemovingRequest = function () { - - editor.toolbar.settings.actions.classList.remove('opened'); - }; - - settings.confirmRemovingRequest = function () { - - var currentBlock = editor.content.currentNode, - firstLevelBlocksCount; - - currentBlock.remove(); - - firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; - - /** - * If all blocks are removed - */ - if (firstLevelBlocksCount === 0) { - - /** update currentNode variable */ - editor.content.currentNode = null; - - /** Inserting new empty initial block */ - editor.ui.addInitialBlock(); - } - - editor.ui.saveInputs(); - - editor.toolbar.close(); - }; - - settings.showRemoveActions = function () { - - editor.toolbar.settings.actions.classList.add('opened'); - }; - - settings.hideRemoveActions = function () { - - editor.toolbar.settings.actions.classList.remove('opened'); - }; - - return settings; - }({}); - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Inline toolbar - * - * Contains from tools: - * Bold, Italic, Underline and Anchor - * - * @author Codex Team - * @version 1.0 - */ - - module.exports = function (inline) { - - var editor = codex.editor; - - inline.buttonsOpened = null; - inline.actionsOpened = null; - inline.wrappersOffset = null; - - /** - * saving selection that need for execCommand for styling - * - */ - inline.storedSelection = null; - - /** - * @protected - * - * Open inline toobar - */ - inline.show = function () { - - var currentNode = editor.content.currentNode, - tool = currentNode.dataset.tool, - plugin; - - /** - * tool allowed to open inline toolbar - */ - plugin = editor.tools[tool]; - - if (!plugin.showInlineToolbar) return; - - var selectedText = inline.getSelectionText(), - toolbar = editor.nodes.inlineToolbar.wrapper; - - if (selectedText.length > 0) { - - /** Move toolbar and open */ - editor.toolbar.inline.move(); - - /** Open inline toolbar */ - toolbar.classList.add('opened'); - - /** show buttons of inline toolbar */ - editor.toolbar.inline.showButtons(); - } - }; - - /** - * @protected - * - * Closes inline toolbar - */ - inline.close = function () { - - var toolbar = editor.nodes.inlineToolbar.wrapper; - - toolbar.classList.remove('opened'); - }; - - /** - * @private - * - * Moving toolbar - */ - inline.move = function () { - - if (!this.wrappersOffset) { - - this.wrappersOffset = this.getWrappersOffset(); - } - - var coords = this.getSelectionCoords(), - defaultOffset = 0, - toolbar = editor.nodes.inlineToolbar.wrapper, - newCoordinateX, - newCoordinateY; - - if (toolbar.offsetHeight === 0) { - - defaultOffset = 40; - } - - newCoordinateX = coords.x - this.wrappersOffset.left; - newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight; - - toolbar.style.transform = 'translate3D(' + Math.floor(newCoordinateX) + 'px, ' + Math.floor(newCoordinateY) + 'px, 0)'; - - /** Close everything */ - editor.toolbar.inline.closeButtons(); - editor.toolbar.inline.closeAction(); - }; - - /** - * @private - * - * Tool Clicked - */ - - inline.toolClicked = function (event, type) { - - /** - * For simple tools we use default browser function - * For more complicated tools, we should write our own behavior - */ - switch (type) { - case 'createLink': - editor.toolbar.inline.createLinkAction(event, type);break; - default: - editor.toolbar.inline.defaultToolAction(type);break; - } - - /** - * highlight buttons - * after making some action - */ - editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); - }; - - /** - * @private - * - * Saving wrappers offset in DOM - */ - inline.getWrappersOffset = function () { - - var wrapper = editor.nodes.wrapper, - offset = this.getOffset(wrapper); - - this.wrappersOffset = offset; - return offset; - }; - - /** - * @private - * - * Calculates offset of DOM element - * - * @param el - * @returns {{top: number, left: number}} - */ - inline.getOffset = function (el) { - - var _x = 0; - var _y = 0; - - while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) { - - _x += el.offsetLeft + el.clientLeft; - _y += el.offsetTop + el.clientTop; - el = el.offsetParent; - } - return { top: _y, left: _x }; - }; - - /** - * @private - * - * Calculates position of selected text - * @returns {{x: number, y: number}} - */ - inline.getSelectionCoords = function () { - - var sel = document.selection, - range; - var x = 0, - y = 0; - - if (sel) { - - if (sel.type != 'Control') { - - range = sel.createRange(); - range.collapse(true); - x = range.boundingLeft; - y = range.boundingTop; - } - } else if (window.getSelection) { - - sel = window.getSelection(); - - if (sel.rangeCount) { - - range = sel.getRangeAt(0).cloneRange(); - if (range.getClientRects) { - - range.collapse(true); - var rect = range.getClientRects()[0]; - - if (!rect) { - - return; - } - - x = rect.left; - y = rect.top; - } - } - } - return { x: x, y: y }; - }; - - /** - * @private - * - * Returns selected text as String - * @returns {string} - */ - inline.getSelectionText = function () { - - var selectedText = ''; - - // all modern browsers and IE9+ - if (window.getSelection) { - - selectedText = window.getSelection().toString(); - } - - return selectedText; - }; - - /** Opens buttons block */ - inline.showButtons = function () { - - var buttons = editor.nodes.inlineToolbar.buttons; - - buttons.classList.add('opened'); - - editor.toolbar.inline.buttonsOpened = true; - - /** highlight buttons */ - editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight); - }; - - /** Makes buttons disappear */ - inline.closeButtons = function () { - - var buttons = editor.nodes.inlineToolbar.buttons; - - buttons.classList.remove('opened'); - - editor.toolbar.inline.buttonsOpened = false; - }; - - /** Open buttons defined action if exist */ - inline.showActions = function () { - - var action = editor.nodes.inlineToolbar.actions; - - action.classList.add('opened'); - - editor.toolbar.inline.actionsOpened = true; - }; - - /** Close actions block */ - inline.closeAction = function () { - - var action = editor.nodes.inlineToolbar.actions; - - action.innerHTML = ''; - action.classList.remove('opened'); - editor.toolbar.inline.actionsOpened = false; - }; - - /** - * Callback for keydowns in inline toolbar "Insert link..." input - */ - var inlineToolbarAnchorInputKeydown_ = function inlineToolbarAnchorInputKeydown_(event) { - - if (event.keyCode != editor.core.keys.ENTER) { - - return; - } - - var editable = editor.content.currentNode, - storedSelection = editor.toolbar.inline.storedSelection; - - editor.toolbar.inline.restoreSelection(editable, storedSelection); - editor.toolbar.inline.setAnchor(this.value); - - /** - * Preventing events that will be able to happen - */ - event.preventDefault(); - event.stopImmediatePropagation(); - - editor.toolbar.inline.clearRange(); - }; - - /** Action for link creation or for setting anchor */ - inline.createLinkAction = function (event) { - - var isActive = this.isLinkActive(); - - var editable = editor.content.currentNode, - storedSelection = editor.toolbar.inline.saveSelection(editable); - - /** Save globally selection */ - editor.toolbar.inline.storedSelection = storedSelection; - - if (isActive) { - - /** - * Changing stored selection. if we want to remove anchor from word - * we should remove anchor from whole word, not only selected part. - * The solution is than we get the length of current link - * Change start position to - end of selection minus length of anchor - */ - editor.toolbar.inline.restoreSelection(editable, storedSelection); - - editor.toolbar.inline.defaultToolAction('unlink'); - } else { - - /** Create input and close buttons */ - var action = editor.draw.inputForLink(); - - editor.nodes.inlineToolbar.actions.appendChild(action); - - editor.toolbar.inline.closeButtons(); - editor.toolbar.inline.showActions(); - - /** - * focus to input - * Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus - * Prevents event after showing input and when we need to focus an input which is in unexisted form - */ - action.focus(); - event.preventDefault(); - - /** Callback to link action */ - editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false); - } - }; - - inline.isLinkActive = function () { - - var isActive = false; - - editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) { - - var dataType = tool.dataset.type; - - if (dataType == 'link' && tool.classList.contains('hightlighted')) { - - isActive = true; - } - }); - - return isActive; - }; - - /** default action behavior of tool */ - inline.defaultToolAction = function (type) { - - document.execCommand(type, false, null); - }; - - /** - * @private - * - * Sets URL - * - * @param {String} url - URL - */ - inline.setAnchor = function (url) { - - document.execCommand('createLink', false, url); - - /** Close after URL inserting */ - editor.toolbar.inline.closeAction(); - }; - - /** - * @private - * - * Saves selection - */ - inline.saveSelection = function (containerEl) { - - var range = window.getSelection().getRangeAt(0), - preSelectionRange = range.cloneRange(), - start; - - preSelectionRange.selectNodeContents(containerEl); - preSelectionRange.setEnd(range.startContainer, range.startOffset); - - start = preSelectionRange.toString().length; - - return { - start: start, - end: start + range.toString().length - }; - }; - - /** - * @private - * - * Sets to previous selection (Range) - * - * @param {Element} containerEl - editable element where we restore range - * @param {Object} savedSel - range basic information to restore - */ - inline.restoreSelection = function (containerEl, savedSel) { - - var range = document.createRange(), - charIndex = 0; - - range.setStart(containerEl, 0); - range.collapse(true); - - var nodeStack = [containerEl], - node, - foundStart = false, - stop = false, - nextCharIndex; - - while (!stop && (node = nodeStack.pop())) { - - if (node.nodeType == 3) { - - nextCharIndex = charIndex + node.length; - - if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) { - - range.setStart(node, savedSel.start - charIndex); - foundStart = true; - } - if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) { - - range.setEnd(node, savedSel.end - charIndex); - stop = true; - } - charIndex = nextCharIndex; - } else { - - var i = node.childNodes.length; - - while (i--) { - - nodeStack.push(node.childNodes[i]); - } - } - } - - var sel = window.getSelection(); - - sel.removeAllRanges(); - sel.addRange(range); - }; - - /** - * @private - * - * Removes all ranges from window selection - */ - inline.clearRange = function () { - - var selection = window.getSelection(); - - selection.removeAllRanges(); - }; - - /** - * @private - * - * sets or removes hightlight - */ - inline.hightlight = function (tool) { - - var dataType = tool.dataset.type; - - if (document.queryCommandState(dataType)) { - - editor.toolbar.inline.setButtonHighlighted(tool); - } else { - - editor.toolbar.inline.removeButtonsHighLight(tool); - } - - /** - * - * hightlight for anchors - */ - var selection = window.getSelection(), - tag = selection.anchorNode.parentNode; - - if (tag.tagName == 'A' && dataType == 'link') { - - editor.toolbar.inline.setButtonHighlighted(tool); - } - }; - - /** - * @private - * - * Mark button if text is already executed - */ - inline.setButtonHighlighted = function (button) { - - button.classList.add('hightlighted'); - - /** At link tool we also change icon */ - if (button.dataset.type == 'link') { - - var icon = button.childNodes[0]; - - icon.classList.remove('ce-icon-link'); - icon.classList.add('ce-icon-unlink'); - } - }; - - /** - * @private - * - * Removes hightlight - */ - inline.removeButtonsHighLight = function (button) { - - button.classList.remove('hightlighted'); - - /** At link tool we also change icon */ - if (button.dataset.type == 'link') { - - var icon = button.childNodes[0]; - - icon.classList.remove('ce-icon-unlink'); - icon.classList.add('ce-icon-link'); - } - }; - - return inline; - }({}); - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor toolbox - * - * All tools be able to appended here - * - * @author Codex Team - * @version 1.0 - */ - - module.exports = function (toolbox) { - - var editor = codex.editor; - - toolbox.opened = false; - toolbox.openedOnBlock = null; - - /** Shows toolbox */ - toolbox.open = function () { - - /** Close setting if toolbox is opened */ - if (editor.toolbar.settings.opened) { - - editor.toolbar.settings.close(); - } - - /** Add 'toolbar-opened' class for current block **/ - toolbox.openedOnBlock = editor.content.currentNode; - toolbox.openedOnBlock.classList.add('toolbar-opened'); - - /** display toolbox */ - editor.nodes.toolbox.classList.add('opened'); - - /** Animate plus button */ - editor.nodes.plusButton.classList.add('clicked'); - - /** toolbox state */ - editor.toolbar.toolbox.opened = true; - }; - - /** Closes toolbox */ - toolbox.close = function () { - - /** Remove 'toolbar-opened' class from current block **/ - if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened'); - toolbox.openedOnBlock = null; - - /** Makes toolbox disappear */ - editor.nodes.toolbox.classList.remove('opened'); - - /** Rotate plus button */ - editor.nodes.plusButton.classList.remove('clicked'); - - /** toolbox state */ - editor.toolbar.toolbox.opened = false; - - editor.toolbar.current = null; - }; - - toolbox.leaf = function () { - - var currentTool = editor.toolbar.current, - tools = Object.keys(editor.tools), - barButtons = editor.nodes.toolbarButtons, - nextToolIndex = 0, - toolToSelect = void 0, - visibleTool = void 0, - tool = void 0; - - if (!currentTool) { - - /** Get first tool from object*/ - for (tool in editor.tools) { - - if (editor.tools[tool].displayInToolbox) { - - break; - } - - nextToolIndex++; - } - } else { - - nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length; - visibleTool = tools[nextToolIndex]; - - while (!editor.tools[visibleTool].displayInToolbox) { - - nextToolIndex = (nextToolIndex + 1) % tools.length; - visibleTool = tools[nextToolIndex]; - } - } - - toolToSelect = tools[nextToolIndex]; - - for (var button in barButtons) { - - barButtons[button].classList.remove('selected'); - } - - barButtons[toolToSelect].classList.add('selected'); - editor.toolbar.current = toolToSelect; - }; - - /** - * Transforming selected node type into selected toolbar element type - * @param {event} event - */ - toolbox.toolClicked = function (event) { - - /** - * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty - */ - var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'], - tool = editor.tools[editor.toolbar.current], - workingNode = editor.content.currentNode, - currentInputIndex = editor.caret.inputIndex, - newBlockContent, - appendCallback, - blockData; - - /** Make block from plugin */ - newBlockContent = tool.render(); - - /** information about block */ - blockData = { - block: newBlockContent, - type: tool.type, - stretched: false - }; - - if (workingNode && UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 && workingNode.textContent.trim() === '') { - - /** Replace current block */ - editor.content.switchBlock(workingNode, newBlockContent, tool.type); - } else { - - /** Insert new Block from plugin */ - editor.content.insertBlock(blockData); - - /** increase input index */ - currentInputIndex++; - } - - /** Fire tool append callback */ - appendCallback = tool.appendCallback; - - if (appendCallback && typeof appendCallback == 'function') { - - appendCallback.call(event); - } - - window.setTimeout(function () { - - /** Set caret to current block */ - editor.caret.setToBlock(currentInputIndex); - }, 10); - - /** - * Changing current Node - */ - editor.content.workingNodeChanged(); - - /** - * Move toolbar when node is changed - */ - editor.toolbar.move(); - }; - - return toolbox; - }({}); - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * @module Codex Editor Callbacks module - * @description Module works with editor added Elements - * - * @author Codex Team - * @version 1.4.0 - */ - - module.exports = function (callbacks) { - - var editor = codex.editor; - - /** - * used by UI module - * @description Routes all keydowns on document - * @param {Object} event - */ - callbacks.globalKeydown = function (event) { - - switch (event.keyCode) { - case editor.core.keys.ENTER: - enterKeyPressed_(event);break; - } - }; - - /** - * used by UI module - * @description Routes all keydowns on redactors area - * @param {Object} event - */ - callbacks.redactorKeyDown = function (event) { - - switch (event.keyCode) { - case editor.core.keys.TAB: - tabKeyPressedOnRedactorsZone_(event);break; - case editor.core.keys.ENTER: - enterKeyPressedOnRedactorsZone_(event);break; - case editor.core.keys.ESC: - escapeKeyPressedOnRedactorsZone_(event);break; - default: - defaultKeyPressedOnRedactorsZone_(event);break; - } - }; - - /** - * used by UI module - * @description Routes all keyup events - * @param {Object} event - */ - callbacks.globalKeyup = function (event) { - - switch (event.keyCode) { - case editor.core.keys.UP: - case editor.core.keys.LEFT: - case editor.core.keys.RIGHT: - case editor.core.keys.DOWN: - arrowKeyPressed_(event);break; - } - }; - - /** - * @param {Object} event - * @private - * - * Handles behaviour when tab pressed - * @description if Content is empty show toolbox (if it is closed) or leaf tools - * uses Toolbars toolbox module to handle the situation - */ - var tabKeyPressedOnRedactorsZone_ = function tabKeyPressedOnRedactorsZone_(event) { - - /** - * Wait for solution. Would like to know the behaviour - * @todo Add spaces - */ - event.preventDefault(); - - if (!editor.core.isBlockEmpty(editor.content.currentNode)) { - - return; - } - - if (!editor.toolbar.opened) { - - editor.toolbar.open(); - } - - if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) { - - editor.toolbar.toolbox.open(); - } else { - - editor.toolbar.toolbox.leaf(); - } - }; - - /** - * Handles global EnterKey Press - * @see enterPressedOnBlock_ - * @param {Object} event - */ - var enterKeyPressed_ = function enterKeyPressed_() { - - if (editor.content.editorAreaHightlighted) { - - /** - * it means that we lose input index, saved index before is not correct - * therefore we need to set caret when we insert new block - */ - editor.caret.inputIndex = -1; - - enterPressedOnBlock_(); - } - }; - - /** - * Callback for enter key pressing in first-level block area - * - * @param {Event} event - * @private - * - * @description Inserts new block with initial type from settings - */ - var enterPressedOnBlock_ = function enterPressedOnBlock_() { - - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - - editor.content.insertBlock({ - type: NEW_BLOCK_TYPE, - block: editor.tools[NEW_BLOCK_TYPE].render() - }, true); - - editor.toolbar.move(); - editor.toolbar.open(); - }; - - /** - * ENTER key handler - * - * @param {Object} event - * @private - * - * @description Makes new block with initial type from settings - */ - var enterKeyPressedOnRedactorsZone_ = function enterKeyPressedOnRedactorsZone_(event) { - - if (event.target.contentEditable == 'true') { - - /** Update input index */ - editor.caret.saveCurrentInputIndex(); - } - - var currentInputIndex = editor.caret.getCurrentInputIndex() || 0, - workingNode = editor.content.currentNode, - tool = workingNode.dataset.tool, - isEnterPressedOnToolbar = editor.toolbar.opened && editor.toolbar.current && event.target == editor.state.inputs[currentInputIndex]; - - /** The list of tools which needs the default browser behaviour */ - var enableLineBreaks = editor.tools[tool].enableLineBreaks; - - /** This type of block creates when enter is pressed */ - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - - /** - * When toolbar is opened, select tool instead of making new paragraph - */ - if (isEnterPressedOnToolbar) { - - event.preventDefault(); - - editor.toolbar.toolbox.toolClicked(event); - - editor.toolbar.close(); - - /** - * Stop other listeners callback executions - */ - event.stopPropagation(); - event.stopImmediatePropagation(); - - return; - } - - /** - * Allow paragraph lineBreaks with shift enter - * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation - */ - if (event.shiftKey || enableLineBreaks) { - - event.stopPropagation(); - event.stopImmediatePropagation(); - return; - } - - var currentSelection = window.getSelection(), - currentSelectedNode = currentSelection.anchorNode, - caretAtTheEndOfText = editor.caret.position.atTheEnd(), - isTextNodeHasParentBetweenContenteditable = false; - - /** - * Allow making new

in same block by SHIFT+ENTER and forbids to prevent default browser behaviour - */ - if (event.shiftKey && !enableLineBreaks) { - - editor.callback.enterPressedOnBlock(editor.content.currentBlock, event); - event.preventDefault(); - return; - } - - /** - * Workaround situation when caret at the Text node that has some wrapper Elements - * Split block cant handle this. - * We need to save default behavior - */ - isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true'; - - /** - * Split blocks when input has several nodes and caret placed in textNode - */ - if (currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT && !isTextNodeHasParentBetweenContenteditable && !caretAtTheEndOfText) { - - event.preventDefault(); - - editor.core.log('Splitting Text node...'); - - editor.content.splitBlock(currentInputIndex); - - /** Show plus button when next input after split is empty*/ - if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) { - - editor.toolbar.showPlusButton(); - } - } else { - - var islastNode = editor.content.isLastNode(currentSelectedNode); - - if (islastNode && caretAtTheEndOfText) { - - event.preventDefault(); - event.stopPropagation(); - event.stopImmediatePropagation(); - - editor.core.log('ENTER clicked in last textNode. Create new BLOCK'); - - editor.content.insertBlock({ - type: NEW_BLOCK_TYPE, - block: editor.tools[NEW_BLOCK_TYPE].render() - }, true); - - editor.toolbar.move(); - editor.toolbar.open(); - - /** Show plus button with empty block */ - editor.toolbar.showPlusButton(); - } - } - - /** get all inputs after new appending block */ - editor.ui.saveInputs(); - }; - - /** - * Escape behaviour - * @param event - * @private - * - * @description Closes toolbox and toolbar. Prevents default behaviour - */ - var escapeKeyPressedOnRedactorsZone_ = function escapeKeyPressedOnRedactorsZone_(event) { - - /** Close all toolbar */ - editor.toolbar.close(); - - /** Close toolbox */ - editor.toolbar.toolbox.close(); - - event.preventDefault(); - }; - - /** - * @param {Event} event - * @private - * - * closes and moves toolbar - */ - var arrowKeyPressed_ = function arrowKeyPressed_(event) { - - editor.content.workingNodeChanged(); - - /* Closing toolbar */ - editor.toolbar.close(); - editor.toolbar.move(); - }; - - /** - * @private - * @param {Event} event - * - * @description Closes all opened bars from toolbar. - * If block is mark, clears highlightning - */ - var defaultKeyPressedOnRedactorsZone_ = function defaultKeyPressedOnRedactorsZone_() { - - editor.toolbar.close(); - - if (!editor.toolbar.inline.actionsOpened) { - - editor.toolbar.inline.close(); - editor.content.clearMark(); - } - }; - - /** - * Handler when clicked on redactors area - * - * @protected - * @param event - * - * @description Detects clicked area. If it is first-level block area, marks as detected and - * on next enter press will be inserted new block - * Otherwise, save carets position (input index) and put caret to the editable zone. - * - * @see detectWhenClickedOnFirstLevelBlockArea_ - * - */ - callbacks.redactorClicked = function (event) { - - detectWhenClickedOnFirstLevelBlockArea_(); - - editor.content.workingNodeChanged(event.target); - editor.ui.saveInputs(); - - var selectedText = editor.toolbar.inline.getSelectionText(), - firstLevelBlock; - - /** If selection range took off, then we hide inline toolbar */ - if (selectedText.length === 0) { - - editor.toolbar.inline.close(); - } - - /** Update current input index in memory when caret focused into existed input */ - if (event.target.contentEditable == 'true') { - - editor.caret.saveCurrentInputIndex(); - } - - if (editor.content.currentNode === null) { - - /** - * If inputs in redactor does not exits, then we put input index 0 not -1 - */ - var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0; - - /** If we have any inputs */ - if (editor.state.inputs.length) { - - /** getting firstlevel parent of input */ - firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]); - } - - /** If input is empty, then we set caret to the last input */ - if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) { - - editor.caret.setToBlock(indexOfLastInput); - } else { - - /** Create new input when caret clicked in redactors area */ - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin; - - editor.content.insertBlock({ - type: NEW_BLOCK_TYPE, - block: editor.tools[NEW_BLOCK_TYPE].render() - }); - - /** If there is no inputs except inserted */ - if (editor.state.inputs.length === 1) { - - editor.caret.setToBlock(indexOfLastInput); - } else { - - /** Set caret to this appended input */ - editor.caret.setToNextBlock(indexOfLastInput); - } - } - } else { - - /** Close all panels */ - editor.toolbar.settings.close(); - editor.toolbar.toolbox.close(); - } - - /** - * Move toolbar and open - */ - editor.toolbar.move(); - editor.toolbar.open(); - - var inputIsEmpty = !editor.content.currentNode.textContent.trim(), - currentNodeType = editor.content.currentNode.dataset.tool, - isInitialType = currentNodeType == editor.settings.initialBlockPlugin; - - /** Hide plus buttons */ - editor.toolbar.hidePlusButton(); - - if (!inputIsEmpty) { - - /** Mark current block */ - editor.content.markBlock(); - } - - if (isInitialType && inputIsEmpty) { - - /** Show plus button */ - editor.toolbar.showPlusButton(); - } - }; - - /** - * This method allows to define, is caret in contenteditable element or not. - * - * @private - * - * @description Otherwise, if we get TEXT node from range container, that will means we have input index. - * In this case we use default browsers behaviour (if plugin allows that) or overwritten action. - * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always - * specifies to the first-level block. Other cases we just ignore. - */ - var detectWhenClickedOnFirstLevelBlockArea_ = function detectWhenClickedOnFirstLevelBlockArea_() { - - var selection = window.getSelection(), - anchorNode = selection.anchorNode, - flag = false; - - if (selection.rangeCount === 0) { - - editor.content.editorAreaHightlighted = true; - } else { - - if (!editor.core.isDomNode(anchorNode)) { - - anchorNode = anchorNode.parentNode; - } - - /** Already founded, without loop */ - if (anchorNode.contentEditable == 'true') { - - flag = true; - } - - while (anchorNode.contentEditable != 'true') { - - anchorNode = anchorNode.parentNode; - - if (anchorNode.contentEditable == 'true') { - - flag = true; - } - - if (anchorNode == document.body) { - - break; - } - } - - /** If editable element founded, flag is "TRUE", Therefore we return "FALSE" */ - editor.content.editorAreaHightlighted = !flag; - } - }; - - /** - * Toolbar button click handler - * - * @param {Object} event - cursor to the button - * @protected - * - * @description gets current tool and calls render method - */ - callbacks.toolbarButtonClicked = function (event) { - - var button = this; - - editor.toolbar.current = button.dataset.type; - - editor.toolbar.toolbox.toolClicked(event); - editor.toolbar.close(); - }; - - /** - * Show or Hide toolbox when plus button is clicked - */ - callbacks.plusButtonClicked = function () { - - if (!editor.nodes.toolbox.classList.contains('opened')) { - - editor.toolbar.toolbox.open(); - } else { - - editor.toolbar.toolbox.close(); - } - }; - - /** - * Block handlers for KeyDown events - * - * @protected - * @param {Object} event - * - * Handles keydowns on block - * @see blockRightOrDownArrowPressed_ - * @see backspacePressed_ - * @see blockLeftOrUpArrowPressed_ - */ - callbacks.blockKeydown = function (event) { - - var block = event.target; // event.target is input - - switch (event.keyCode) { - - case editor.core.keys.DOWN: - case editor.core.keys.RIGHT: - blockRightOrDownArrowPressed_(event); - break; - - case editor.core.keys.BACKSPACE: - backspacePressed_(block, event); - break; - - case editor.core.keys.UP: - case editor.core.keys.LEFT: - blockLeftOrUpArrowPressed_(event); - break; - - } - }; - - /** - * RIGHT or DOWN keydowns on block - * - * @param {Object} event - * @private - * - * @description watches the selection and gets closest editable element. - * Uses method getDeepestTextNodeFromPosition to get the last node of next block - * Sets caret if it is contenteditable - */ - var blockRightOrDownArrowPressed_ = function blockRightOrDownArrowPressed_(event) { - - var selection = window.getSelection(), - inputs = editor.state.inputs, - focusedNode = selection.anchorNode, - focusedNodeHolder; - - /** Check for caret existance */ - if (!focusedNode) { - - return false; - } - - /** Looking for closest (parent) contentEditable element of focused node */ - while (focusedNode.contentEditable != 'true') { - - focusedNodeHolder = focusedNode.parentNode; - focusedNode = focusedNodeHolder; - } - - /** Input index in DOM level */ - var editableElementIndex = 0; - - while (focusedNode != inputs[editableElementIndex]) { - - editableElementIndex++; - } - - /** - * Founded contentEditable element doesn't have childs - * Or maybe New created block - */ - if (!focusedNode.textContent) { - - editor.caret.setToNextBlock(editableElementIndex); - return; - } - - /** - * Do nothing when caret doesn not reaches the end of last child - */ - var caretInLastChild = false, - caretAtTheEndOfText = false; - - var lastChild, deepestTextnode; - - lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1]; - - if (editor.core.isDomNode(lastChild)) { - - deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length); - } else { - - deepestTextnode = lastChild; - } - - caretInLastChild = selection.anchorNode == deepestTextnode; - caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset; - - if (!caretInLastChild || !caretAtTheEndOfText) { - - editor.core.log('arrow [down|right] : caret does not reached the end'); - return false; - } - - editor.caret.setToNextBlock(editableElementIndex); - }; - - /** - * LEFT or UP keydowns on block - * - * @param {Object} event - * @private - * - * watches the selection and gets closest editable element. - * Uses method getDeepestTextNodeFromPosition to get the last node of previous block - * Sets caret if it is contenteditable - * - */ - var blockLeftOrUpArrowPressed_ = function blockLeftOrUpArrowPressed_(event) { - - var selection = window.getSelection(), - inputs = editor.state.inputs, - focusedNode = selection.anchorNode, - focusedNodeHolder; - - /** Check for caret existance */ - if (!focusedNode) { - - return false; - } - - /** - * LEFT or UP not at the beginning - */ - if (selection.anchorOffset !== 0) { - - return false; - } - - /** Looking for parent contentEditable block */ - while (focusedNode.contentEditable != 'true') { - - focusedNodeHolder = focusedNode.parentNode; - focusedNode = focusedNodeHolder; - } - - /** Input index in DOM level */ - var editableElementIndex = 0; - - while (focusedNode != inputs[editableElementIndex]) { - - editableElementIndex++; - } - - /** - * Do nothing if caret is not at the beginning of first child - */ - var caretInFirstChild = false, - caretAtTheBeginning = false; - - var firstChild, deepestTextnode; - - /** - * Founded contentEditable element doesn't have childs - * Or maybe New created block - */ - if (!focusedNode.textContent) { - - editor.caret.setToPreviousBlock(editableElementIndex); - return; - } - - firstChild = focusedNode.childNodes[0]; - - if (editor.core.isDomNode(firstChild)) { - - deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0); - } else { - - deepestTextnode = firstChild; - } - - caretInFirstChild = selection.anchorNode == deepestTextnode; - caretAtTheBeginning = selection.anchorOffset === 0; - - if (caretInFirstChild && caretAtTheBeginning) { - - editor.caret.setToPreviousBlock(editableElementIndex); - } - }; - - /** - * Handles backspace keydown - * - * @param {Element} block - * @param {Object} event - * @private - * - * @description if block is empty, delete the block and set caret to the previous block - * If block is not empty, try to merge two blocks - current and previous - * But it we try'n to remove first block, then we should set caret to the next block, not previous. - * If we removed the last block, create new one - */ - var backspacePressed_ = function backspacePressed_(block, event) { - - var currentInputIndex = editor.caret.getCurrentInputIndex(), - range, - selectionLength, - firstLevelBlocksCount; - - if (editor.core.isNativeInput(event.target)) { - - /** If input value is empty - remove block */ - if (event.target.value.trim() == '') { - - block.remove(); - } else { - - return; - } - } - - if (block.textContent.trim()) { - - range = editor.content.getRange(); - selectionLength = range.endOffset - range.startOffset; - - if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) { - - editor.content.mergeBlocks(currentInputIndex); - } else { - - return; - } - } - - if (!selectionLength) { - - block.remove(); - } - - firstLevelBlocksCount = editor.nodes.redactor.childNodes.length; - - /** - * If all blocks are removed - */ - if (firstLevelBlocksCount === 0) { - - /** update currentNode variable */ - editor.content.currentNode = null; - - /** Inserting new empty initial block */ - editor.ui.addInitialBlock(); - - /** Updating inputs state after deleting last block */ - editor.ui.saveInputs(); - - /** Set to current appended block */ - window.setTimeout(function () { - - editor.caret.setToPreviousBlock(1); - }, 10); - } else { - - if (editor.caret.inputIndex !== 0) { - - /** Target block is not first */ - editor.caret.setToPreviousBlock(editor.caret.inputIndex); - } else { - - /** If we try to delete first block */ - editor.caret.setToNextBlock(editor.caret.inputIndex); - } - } - - editor.toolbar.move(); - - if (!editor.toolbar.opened) { - - editor.toolbar.open(); - } - - /** Updating inputs state */ - editor.ui.saveInputs(); - - /** Prevent default browser behaviour */ - event.preventDefault(); - }; - - /** - * used by UI module - * Clicks on block settings button - * - * @param {Object} event - * @protected - * @description Opens toolbar settings - */ - callbacks.showSettingsButtonClicked = function (event) { - - /** - * Get type of current block - * It uses to append settings from tool.settings property. - * ... - * Type is stored in data-type attribute on block - */ - var currentToolType = editor.content.currentNode.dataset.tool; - - editor.toolbar.settings.toggle(currentToolType); - - /** Close toolbox when settings button is active */ - editor.toolbar.toolbox.close(); - editor.toolbar.settings.hideRemoveActions(); - }; - - return callbacks; - }({}); - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor Draw module - * - * @author Codex Team - * @version 1.0. - */ - - module.exports = function (draw) { - - /** - * Base editor wrapper - */ - draw.wrapper = function () { - - var wrapper = document.createElement('div'); - - wrapper.className += 'codex-editor'; - - return wrapper; - }; - - /** - * Content-editable holder - */ - draw.redactor = function () { - - var redactor = document.createElement('div'); - - redactor.className += 'ce-redactor'; - - return redactor; - }; - - draw.ceBlock = function () { - - var block = document.createElement('DIV'); - - block.className += 'ce_block'; - - return block; - }; - - /** - * Empty toolbar with toggler - */ - draw.toolbar = function () { - - var bar = document.createElement('div'); - - bar.className += 'ce-toolbar'; - - return bar; - }; - - draw.toolbarContent = function () { - - var wrapper = document.createElement('DIV'); - - wrapper.classList.add('ce-toolbar__content'); - - return wrapper; - }; - - /** - * Inline toolbar - */ - draw.inlineToolbar = function () { - - var bar = document.createElement('DIV'); - - bar.className += 'ce-toolbar-inline'; - - return bar; - }; - - /** - * Wrapper for inline toobar buttons - */ - draw.inlineToolbarButtons = function () { - - var wrapper = document.createElement('DIV'); - - wrapper.className += 'ce-toolbar-inline__buttons'; - - return wrapper; - }; - - /** - * For some actions - */ - draw.inlineToolbarActions = function () { - - var wrapper = document.createElement('DIV'); - - wrapper.className += 'ce-toolbar-inline__actions'; - - return wrapper; - }; - - draw.inputForLink = function () { - - var input = document.createElement('INPUT'); - - input.type = 'input'; - input.className += 'inputForLink'; - input.placeholder = 'Вставьте ссылку ...'; - input.setAttribute('form', 'defaultForm'); - - input.setAttribute('autofocus', 'autofocus'); - - return input; - }; - - /** - * @todo Desc - */ - draw.blockButtons = function () { - - var block = document.createElement('div'); - - block.className += 'ce-toolbar__actions'; - - return block; - }; - - /** - * Block settings panel - */ - draw.blockSettings = function () { - - var settings = document.createElement('div'); - - settings.className += 'ce-settings'; - - return settings; - }; - - draw.defaultSettings = function () { - - var div = document.createElement('div'); - - div.classList.add('ce-settings_default'); - - return div; - }; - - draw.pluginsSettings = function () { - - var div = document.createElement('div'); - - div.classList.add('ce-settings_plugin'); - - return div; - }; - - draw.plusButton = function () { - - var button = document.createElement('span'); - - button.className = 'ce-toolbar__plus'; - // button.innerHTML = ''; - - return button; - }; - - /** - * Settings button in toolbar - */ - draw.settingsButton = function () { - - var toggler = document.createElement('span'); - - toggler.className = 'ce-toolbar__settings-btn'; - - /** Toggler button*/ - toggler.innerHTML = ''; - - return toggler; - }; - - /** - * Redactor tools wrapper - */ - - draw.toolbox = function () { - - var wrapper = document.createElement('div'); - - wrapper.className = 'ce-toolbar__tools'; - - return wrapper; - }; - - /** - * @protected - * - * Draws tool buttons for toolbox - * - * @param {String} type - * @param {String} classname - * @returns {Element} - */ - draw.toolbarButton = function (type, classname) { - - var button = document.createElement('li'), - toolIcon = document.createElement('i'), - toolTitle = document.createElement('span'); - - button.dataset.type = type; - button.setAttribute('title', type); - - toolIcon.classList.add(classname); - toolTitle.classList.add('ce_toolbar_tools--title'); - - button.appendChild(toolIcon); - button.appendChild(toolTitle); - - return button; - }; - - /** - * @protected - * - * Draws tools for inline toolbar - * - * @param {String} type - * @param {String} classname - */ - draw.toolbarButtonInline = function (type, classname) { - - var button = document.createElement('BUTTON'), - toolIcon = document.createElement('I'); - - button.type = 'button'; - button.dataset.type = type; - toolIcon.classList.add(classname); - - button.appendChild(toolIcon); - - return button; - }; - - /** - * Redactor block - */ - draw.block = function (tagName, content) { - - var node = document.createElement(tagName); - - node.innerHTML = content || ''; - - return node; - }; - - /** - * Creates Node with passed tagName and className - * @param {string} tagName - * @param {string} className - * @param {object} properties - allow to assign properties - */ - draw.node = function (tagName, className, properties) { - - var el = document.createElement(tagName); - - if (className) el.className = className; - - if (properties) { - - for (var name in properties) { - - el[name] = properties[name]; - } - } - - return el; - }; - - /** - * Unavailable plugin block - */ - draw.unavailableBlock = function () { - - var wrapper = document.createElement('DIV'); - - wrapper.classList.add('cdx-unavailable-block'); - - return wrapper; - }; - - return draw; - }({}); - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor Caret Module - * - * @author Codex Team - * @version 1.0 - */ - - module.exports = function (caret) { - - var editor = codex.editor; - - /** - * @var {int} InputIndex - editable element in DOM - */ - caret.inputIndex = null; - - /** - * @var {int} offset - caret position in a text node. - */ - caret.offset = null; - - /** - * @var {int} focusedNodeIndex - we get index of child node from first-level block - */ - caret.focusedNodeIndex = null; - - /** - * Creates Document Range and sets caret to the element. - * @protected - * @uses caret.save — if you need to save caret position - * @param {Element} el - Changed Node. - */ - caret.set = function (el, index, offset) { - - offset = offset || caret.offset || 0; - index = index || caret.focusedNodeIndex || 0; - - var childs = el.childNodes, - nodeToSet; - - if (childs.length === 0) { - - nodeToSet = el; - } else { - - nodeToSet = childs[index]; - } - - /** If Element is INPUT */ - if (el.contentEditable != 'true') { - - el.focus(); - return; - } - - if (editor.core.isDomNode(nodeToSet)) { - - nodeToSet = editor.content.getDeepestTextNodeFromPosition(nodeToSet, nodeToSet.childNodes.length); - } - - var range = document.createRange(), - selection = window.getSelection(); - - window.setTimeout(function () { - - range.setStart(nodeToSet, offset); - range.setEnd(nodeToSet, offset); - - selection.removeAllRanges(); - selection.addRange(range); - - editor.caret.saveCurrentInputIndex(); - }, 20); - }; - - /** - * @protected - * Updates index of input and saves it in caret object - */ - caret.saveCurrentInputIndex = function () { - - /** Index of Input that we paste sanitized content */ - var selection = window.getSelection(), - inputs = editor.state.inputs, - focusedNode = selection.anchorNode, - focusedNodeHolder; - - if (!focusedNode) { - - return; - } - - /** Looking for parent contentEditable block */ - while (focusedNode.contentEditable != 'true') { - - focusedNodeHolder = focusedNode.parentNode; - focusedNode = focusedNodeHolder; - } - - /** Input index in DOM level */ - var editableElementIndex = 0; - - while (focusedNode != inputs[editableElementIndex]) { - - editableElementIndex++; - } - - caret.inputIndex = editableElementIndex; - }; - - /** - * Returns current input index (caret object) - */ - caret.getCurrentInputIndex = function () { - - return caret.inputIndex; - }; - - /** - * @param {int} index - index of first-level block after that we set caret into next input - */ - caret.setToNextBlock = function (index) { - - var inputs = editor.state.inputs, - nextInput = inputs[index + 1]; - - if (!nextInput) { - - editor.core.log('We are reached the end'); - return; - } - - /** - * When new Block created or deleted content of input - * We should add some text node to set caret - */ - if (!nextInput.childNodes.length) { - - var emptyTextElement = document.createTextNode(''); - - nextInput.appendChild(emptyTextElement); - } - - editor.caret.inputIndex = index + 1; - editor.caret.set(nextInput, 0, 0); - editor.content.workingNodeChanged(nextInput); - }; - - /** - * @param {int} index - index of target input. - * Sets caret to input with this index - */ - caret.setToBlock = function (index) { - - var inputs = editor.state.inputs, - targetInput = inputs[index]; - - if (!targetInput) { - - return; - } - - /** - * When new Block created or deleted content of input - * We should add some text node to set caret - */ - if (!targetInput.childNodes.length) { - - var emptyTextElement = document.createTextNode(''); - - targetInput.appendChild(emptyTextElement); - } - - editor.caret.inputIndex = index; - editor.caret.set(targetInput, 0, 0); - editor.content.workingNodeChanged(targetInput); - }; - - /** - * @param {int} index - index of input - */ - caret.setToPreviousBlock = function (index) { - - index = index || 0; - - var inputs = editor.state.inputs, - previousInput = inputs[index - 1], - lastChildNode, - lengthOfLastChildNode, - emptyTextElement; - - if (!previousInput) { - - editor.core.log('We are reached first node'); - return; - } - - lastChildNode = editor.content.getDeepestTextNodeFromPosition(previousInput, previousInput.childNodes.length); - lengthOfLastChildNode = lastChildNode.length; - - /** - * When new Block created or deleted content of input - * We should add some text node to set caret - */ - if (!previousInput.childNodes.length) { - - emptyTextElement = document.createTextNode(''); - previousInput.appendChild(emptyTextElement); - } - editor.caret.inputIndex = index - 1; - editor.caret.set(previousInput, previousInput.childNodes.length - 1, lengthOfLastChildNode); - editor.content.workingNodeChanged(inputs[index - 1]); - }; - - caret.position = { - - atStart: function atStart() { - - var selection = window.getSelection(), - anchorOffset = selection.anchorOffset, - anchorNode = selection.anchorNode, - firstLevelBlock = editor.content.getFirstLevelBlock(anchorNode), - pluginsRender = firstLevelBlock.childNodes[0]; - - if (!editor.core.isDomNode(anchorNode)) { - - anchorNode = anchorNode.parentNode; - } - - var isFirstNode = anchorNode === pluginsRender.childNodes[0], - isOffsetZero = anchorOffset === 0; - - return isFirstNode && isOffsetZero; - }, - - atTheEnd: function atTheEnd() { - - var selection = window.getSelection(), - anchorOffset = selection.anchorOffset, - anchorNode = selection.anchorNode; - - /** Caret is at the end of input */ - return !anchorNode || !anchorNode.length || anchorOffset === anchorNode.length; - } - }; - - /** - * Inserts node at the caret location - * @param {HTMLElement|DocumentFragment} node - */ - caret.insertNode = function (node) { - - var selection, - range, - lastNode = node; - - if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) { - - lastNode = node.lastChild; - } - - selection = window.getSelection(); - - range = selection.getRangeAt(0); - range.deleteContents(); - - range.insertNode(node); - - range.setStartAfter(lastNode); - range.collapse(true); - - selection.removeAllRanges(); - selection.addRange(range); - }; - - return caret; - }({}); - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor Notification Module - * - * @author Codex Team - * @version 1.0 - */ - - module.exports = function (notifications) { - - var editor = codex.editor; - - var queue = []; - - var addToQueue = function addToQueue(settings) { - - queue.push(settings); - - var index = 0; - - while (index < queue.length && queue.length > 5) { - - if (queue[index].type == 'confirm' || queue[index].type == 'prompt') { - - index++; - continue; - } - - queue[index].close(); - queue.splice(index, 1); - } - }; - - notifications.createHolder = function () { - - var holder = editor.draw.node('DIV', 'cdx-notifications-block'); - - editor.nodes.notifications = document.body.appendChild(holder); - - return holder; - }; - - /** - * Error notificator. Shows block with message - * @protected - */ - notifications.errorThrown = function (errorMsg, event) { - - editor.notifications.notification({ message: 'This action is not available currently', type: event.type }); - }; - - /** - * - * Appends notification - * - * settings = { - * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type - * message - notification message - * okMsg - confirm button text (default - 'Ok') - * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types - * confirm - function-handler for ok button click - * cancel - function-handler for cancel button click. Only for confirm and prompt types - * time - time (in seconds) after which notification will close (default - 10s) - * } - * - * @param settings - */ - notifications.notification = function (constructorSettings) { - - /** Private vars and methods */ - var notification = null, - cancel = null, - type = null, - confirm = null, - inputField = null; - - var confirmHandler = function confirmHandler() { - - close(); - - if (typeof confirm !== 'function') { - - return; - } - - if (type == 'prompt') { - - confirm(inputField.value); - return; - } - - confirm(); - }; - - var cancelHandler = function cancelHandler() { - - close(); - - if (typeof cancel !== 'function') { - - return; - } - - cancel(); - }; - - /** Public methods */ - function create(settings) { - - if (!(settings && settings.message)) { - - editor.core.log('Can\'t create notification. Message is missed'); - return; - } - - settings.type = settings.type || 'alert'; - settings.time = settings.time * 1000 || 10000; - - var wrapper = editor.draw.node('DIV', 'cdx-notification'), - message = editor.draw.node('DIV', 'cdx-notification__message'), - input = editor.draw.node('INPUT', 'cdx-notification__input'), - okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'), - cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn'); - - message.textContent = settings.message; - okBtn.textContent = settings.okMsg || 'ОК'; - cancelBtn.textContent = settings.cancelMsg || 'Отмена'; - - editor.listeners.add(okBtn, 'click', confirmHandler); - editor.listeners.add(cancelBtn, 'click', cancelHandler); - - wrapper.appendChild(message); - - if (settings.type == 'prompt') { - - wrapper.appendChild(input); - } - - wrapper.appendChild(okBtn); - - if (settings.type == 'prompt' || settings.type == 'confirm') { - - wrapper.appendChild(cancelBtn); - } - - wrapper.classList.add('cdx-notification-' + settings.type); - wrapper.dataset.type = settings.type; - - notification = wrapper; - type = settings.type; - confirm = settings.confirm; - cancel = settings.cancel; - inputField = input; - - if (settings.type != 'prompt' && settings.type != 'confirm') { - - window.setTimeout(close, settings.time); - } - }; - - /** - * Show notification block - */ - function send() { - - editor.nodes.notifications.appendChild(notification); - inputField.focus(); - - editor.nodes.notifications.classList.add('cdx-notification__notification-appending'); - - window.setTimeout(function () { - - editor.nodes.notifications.classList.remove('cdx-notification__notification-appending'); - }, 100); - - addToQueue({ type: type, close: close }); - }; - - /** - * Remove notification block - */ - function close() { - - notification.remove(); - }; - - if (constructorSettings) { - - create(constructorSettings); - send(); - } - - return { - create: create, - send: send, - close: close - }; - }; - - notifications.clear = function () { - - editor.nodes.notifications.innerHTML = ''; - queue = []; - }; - - return notifications; - }({}); - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - - "use strict"; - - /** - * Codex Editor Parser Module - * - * @author Codex Team - * @version 1.1 - */ - - module.exports = function (parser) { - - var editor = codex.editor; - - /** inserting text */ - parser.insertPastedContent = function (blockType, tag) { - - editor.content.insertBlock({ - type: blockType.type, - block: blockType.render({ - text: tag.innerHTML - }) - }); - }; - - /** - * Check DOM node for display style: separated block or child-view - */ - parser.isFirstLevelBlock = function (node) { - - return node.nodeType == editor.core.nodeTypes.TAG && node.classList.contains(editor.ui.className.BLOCK_CLASSNAME); - }; - - return parser; - }({}); - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - - 'use strict'; - - /** - * Codex Sanitizer - */ - - module.exports = function (sanitizer) { - - /** HTML Janitor library */ - var janitor = __webpack_require__(17); - - /** Codex Editor */ - var editor = codex.editor; - - sanitizer.prepare = function () { - - if (editor.settings.sanitizer && !editor.core.isEmpty(editor.settings.sanitizer)) { - - Config.CUSTOM = editor.settings.sanitizer; - } - }; - - /** - * Basic config - */ - var Config = { - - /** User configuration */ - CUSTOM: null, - - BASIC: { - - tags: { - p: {}, - a: { - href: true, - target: '_blank', - rel: 'nofollow' - } - } - } - }; - - sanitizer.Config = Config; - - /** - * - * @param userCustomConfig - * @returns {*} - * @private - * - * @description If developer uses editor's API, then he can customize sane restrictions. - * Or, sane config can be defined globally in editors initialization. That config will be used everywhere - * At least, if there is no config overrides, that API uses BASIC Default configation - */ - var init_ = function init_(userCustomConfig) { - - var configuration = userCustomConfig || Config.CUSTOM || Config.BASIC; - - return new janitor(configuration); - }; - - /** - * Cleans string from unwanted tags - * @protected - * @param {String} dirtyString - taint string - * @param {Object} customConfig - allowed tags - */ - sanitizer.clean = function (dirtyString, customConfig) { - - var janitorInstance = init_(customConfig); - - return janitorInstance.clean(dirtyString); - }; - - return sanitizer; - }({}); - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - - var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory) { - if (true) { - !(__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__)); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.HTMLJanitor = factory(); - } - }(this, function () { - - /** - * @param {Object} config.tags Dictionary of allowed tags. - * @param {boolean} config.keepNestedBlockElements Default false. - */ - function HTMLJanitor(config) { - - var tagDefinitions = config['tags']; - var tags = Object.keys(tagDefinitions); - - var validConfigValues = tags - .map(function(k) { return typeof tagDefinitions[k]; }) - .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; }); - - if(!validConfigValues) { - throw new Error("The configuration was invalid"); - } - - this.config = config; - } - - // TODO: not exhaustive? - var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE']; - function isBlockElement(node) { - return blockElementNames.indexOf(node.nodeName) !== -1; - } - - var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE']; - function isInlineElement(node) { - return inlineElementNames.indexOf(node.nodeName) !== -1; - } - - HTMLJanitor.prototype.clean = function (html) { - var sandbox = document.createElement('div'); - sandbox.innerHTML = html; - - this._sanitize(sandbox); - - return sandbox.innerHTML; - }; - - HTMLJanitor.prototype._sanitize = function (parentNode) { - var treeWalker = createTreeWalker(parentNode); - var node = treeWalker.firstChild(); - if (!node) { return; } - - do { - // Ignore nodes that have already been sanitized - if (node._sanitized) { - continue; - } - - if (node.nodeType === Node.TEXT_NODE) { - // If this text node is just whitespace and the previous or next element - // sibling is a block element, remove it - // N.B.: This heuristic could change. Very specific to a bug with - // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output - // FIXME: make this an option? - if (node.data.trim() === '' - && ((node.previousElementSibling && isBlockElement(node.previousElementSibling)) - || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) { - parentNode.removeChild(node); - this._sanitize(parentNode); - break; - } else { - continue; - } - } - - // Remove all comments - if (node.nodeType === Node.COMMENT_NODE) { - parentNode.removeChild(node); - this._sanitize(parentNode); - break; - } - - var isInline = isInlineElement(node); - var containsBlockElement; - if (isInline) { - containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement); - } - - // Block elements should not be nested (e.g.

  • ...); if - // they are, we want to unwrap the inner block element. - var isNotTopContainer = !! parentNode.parentNode; - var isNestedBlockElement = - isBlockElement(parentNode) && - isBlockElement(node) && - isNotTopContainer; - - var nodeName = node.nodeName.toLowerCase(); - - var allowedAttrs = getAllowedAttrs(this.config, nodeName, node); - - var isInvalid = isInline && containsBlockElement; - - // Drop tag entirely according to the whitelist *and* if the markup - // is invalid. - if (isInvalid || shouldRejectNode(node, allowedAttrs) - || (!this.config.keepNestedBlockElements && isNestedBlockElement)) { - // Do not keep the inner text of SCRIPT/STYLE elements. - if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) { - while (node.childNodes.length > 0) { - parentNode.insertBefore(node.childNodes[0], node); - } - } - parentNode.removeChild(node); - - this._sanitize(parentNode); - break; - } - - // Sanitize attributes - for (var a = 0; a < node.attributes.length; a += 1) { - var attr = node.attributes[a]; - - if (shouldRejectAttr(attr, allowedAttrs, node)) { - node.removeAttribute(attr.name); - // Shift the array to continue looping. - a = a - 1; - } - } - - // Sanitize children - this._sanitize(node); - - // Mark node as sanitized so it's ignored in future runs - node._sanitized = true; - } while ((node = treeWalker.nextSibling())); - }; - - function createTreeWalker(node) { - return document.createTreeWalker(node, - NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT, - null, false); - } - - function getAllowedAttrs(config, nodeName, node){ - if (typeof config.tags[nodeName] === 'function') { - return config.tags[nodeName](node); - } else { - return config.tags[nodeName]; - } - } - - function shouldRejectNode(node, allowedAttrs){ - if (typeof allowedAttrs === 'undefined') { - return true; - } else if (typeof allowedAttrs === 'boolean') { - return !allowedAttrs; - } - - return false; - } - - function shouldRejectAttr(attr, allowedAttrs, node){ - var attrName = attr.name.toLowerCase(); - - if (allowedAttrs === true){ - return false; - } else if (typeof allowedAttrs[attrName] === 'function'){ - return !allowedAttrs[attrName](attr.value, node); - } else if (typeof allowedAttrs[attrName] === 'undefined'){ - return true; - } else if (allowedAttrs[attrName] === false) { - return true; - } else if (typeof allowedAttrs[attrName] === 'string') { - return (allowedAttrs[attrName] !== attr.value); - } - - return false; - } - - return HTMLJanitor; - - })); - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - - "use strict"; - - /** - * Codex Editor Listeners module - * - * @author Codex Team - * @version 1.0 - */ - - /** - * Module-decorator for event listeners assignment - */ - module.exports = function (listeners) { - - var allListeners = []; - - /** - * Search methods - * - * byElement, byType and byHandler returns array of suitable listeners - * one and all takes element, eventType, and handler and returns first (all) suitable listener - * - */ - listeners.search = function () { - - var byElement = function byElement(element, context) { - - var listenersOnElement = []; - - context = context || allListeners; - - for (var i = 0; i < context.length; i++) { - - var listener = context[i]; - - if (listener.element === element) { - - listenersOnElement.push(listener); - } - } - - return listenersOnElement; - }; - - var byType = function byType(eventType, context) { - - var listenersWithType = []; - - context = context || allListeners; - - for (var i = 0; i < context.length; i++) { - - var listener = context[i]; - - if (listener.type === eventType) { - - listenersWithType.push(listener); - } - } - - return listenersWithType; - }; - - var byHandler = function byHandler(handler, context) { - - var listenersWithHandler = []; - - context = context || allListeners; - - for (var i = 0; i < context.length; i++) { - - var listener = context[i]; - - if (listener.handler === handler) { - - listenersWithHandler.push(listener); - } - } - - return listenersWithHandler; - }; - - var one = function one(element, eventType, handler) { - - var result = allListeners; - - if (element) result = byElement(element, result); - - if (eventType) result = byType(eventType, result); - - if (handler) result = byHandler(handler, result); - - return result[0]; - }; - - var all = function all(element, eventType, handler) { - - var result = allListeners; - - if (element) result = byElement(element, result); - - if (eventType) result = byType(eventType, result); - - if (handler) result = byHandler(handler, result); - - return result; - }; - - return { - byElement: byElement, - byType: byType, - byHandler: byHandler, - one: one, - all: all - }; - }(); - - listeners.add = function (element, eventType, handler, isCapture) { - - element.addEventListener(eventType, handler, isCapture); - - var data = { - element: element, - type: eventType, - handler: handler - }; - - var alreadyAddedListener = listeners.search.one(element, eventType, handler); - - if (!alreadyAddedListener) { - - allListeners.push(data); - } - }; - - listeners.remove = function (element, eventType, handler) { - - element.removeEventListener(eventType, handler); - - var existingListeners = listeners.search.all(element, eventType, handler); - - for (var i = 0; i < existingListeners.length; i++) { - - var index = allListeners.indexOf(existingListeners[i]); - - if (index > 0) { - - allListeners.splice(index, 1); - } - } - }; - - listeners.removeAll = function () { - - allListeners.map(function (current) { - - listeners.remove(current.element, current.type, current.handler); - }); - }; - - listeners.get = function (element, eventType, handler) { - - return listeners.search.all(element, eventType, handler); - }; - - return listeners; - }({}); - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - - 'use strict'; - - var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - - /** - * Codex Editor Destroyer module - * - * @auhor Codex Team - * @version 1.0 - */ - - module.exports = function (destroyer) { - - var editor = codex.editor; - - destroyer.removeNodes = function () { - - editor.nodes.wrapper.remove(); - editor.nodes.notifications.remove(); - }; - - destroyer.destroyPlugins = function () { - - for (var tool in editor.tools) { - - if (typeof editor.tools[tool].destroy === 'function') { - - editor.tools[tool].destroy(); - } - } - }; - - destroyer.destroyScripts = function () { - - var scripts = document.getElementsByTagName('SCRIPT'); - - for (var i = 0; i < scripts.length; i++) { - - if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) { - - scripts[i].remove(); - i--; - } - } - }; - - /** - * Delete editor data from webpage. - * You should send settings argument with boolean flags: - * @param settings.ui- remove redactor event listeners and DOM nodes - * @param settings.scripts - remove redactor scripts from DOM - * @param settings.plugins - remove plugin's objects - * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true - * } - * - */ - destroyer.destroy = function (settings) { - - if (!settings || (typeof settings === 'undefined' ? 'undefined' : _typeof(settings)) !== 'object') { - - return; - } - - if (settings.ui) { - - destroyer.removeNodes(); - editor.listeners.removeAll(); - } - - if (settings.scripts) { - - destroyer.destroyScripts(); - } - - if (settings.plugins) { - - destroyer.destroyPlugins(); - } - - if (settings.ui && settings.scripts && settings.core) { - - delete codex.editor; - } - }; - - return destroyer; - }({}); - -/***/ }), -/* 20 */ -/***/ (function(module, exports) { - - 'use strict'; - - /** - * Codex Editor Paste module - * - * @author Codex Team - * @version 1.1.1 - */ - - module.exports = function (paste) { - - var editor = codex.editor; - - var patterns = []; - - paste.prepare = function () { - - var tools = editor.tools; - - for (var tool in tools) { - - if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) { - - continue; - } - - tools[tool].renderOnPastePatterns.map(function (pattern) { - - patterns.push(pattern); - }); - } - - return Promise.resolve(); - }; - - /** - * Saves data - * @param event - */ - paste.pasted = function (event) { - - var clipBoardData = event.clipboardData || window.clipboardData, - content = clipBoardData.getData('Text'); - - var result = analize(content); - - if (result) { - - event.preventDefault(); - event.stopImmediatePropagation(); - } - - return result; - }; - - /** - * Analizes pated string and calls necessary method - */ - - var analize = function analize(string) { - - var result = false, - content = editor.content.currentNode, - plugin = content.dataset.tool; - - patterns.map(function (pattern) { - - var execArray = pattern.regex.exec(string), - match = execArray && execArray[0]; - - if (match && match === string.trim()) { - - /** current block is not empty */ - if (content.textContent.trim() && plugin == editor.settings.initialBlockPlugin) { - - pasteToNewBlock_(); - } - - pattern.callback(string, pattern); - result = true; - } - }); - - return result; - }; - - var pasteToNewBlock_ = function pasteToNewBlock_() { - - /** Create new initial block */ - editor.content.insertBlock({ - - type: editor.settings.initialBlockPlugin, - block: editor.tools[editor.settings.initialBlockPlugin].render({ - text: '' - }) - - }, false); - }; - - /** - * This method prevents default behaviour. - * - * @param {Object} event - * @protected - * - * @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes. - * Firstly, we need to memorize the caret position. We can do that by getting the range of selection. - * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node - */ - paste.blockPasteCallback = function (event) { - - if (!needsToHandlePasteEvent(event.target)) { - - return; - } - - /** Prevent default behaviour */ - event.preventDefault(); - - /** get html pasted data - dirty data */ - var htmlData = event.clipboardData.getData('text/html'), - plainData = event.clipboardData.getData('text/plain'); - - /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/ - var paragraphs = editor.draw.node('DIV', '', {}), - cleanData, - wrappedData; - - /** Create fragment, that we paste to range after proccesing */ - cleanData = editor.sanitizer.clean(htmlData); - - /** - * We wrap pasted text with

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

    ) whit content, that should be inserted - */ - var insertPastedParagraphs = function insertPastedParagraphs(paragraphs) { - - var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin, - currentNode = editor.content.currentNode; - - paragraphs.forEach(function (paragraph) { - - /** Don't allow empty paragraphs */ - if (editor.core.isBlockEmpty(paragraph)) { - - return; - } - - editor.content.insertBlock({ - type: NEW_BLOCK_TYPE, - block: editor.tools[NEW_BLOCK_TYPE].render({ - text: paragraph.innerHTML - }) - }); - - editor.caret.inputIndex++; - }); - - editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1); - - /** - * If there was no data in working node, remove it - */ - if (editor.core.isBlockEmpty(currentNode)) { - - currentNode.remove(); - editor.ui.saveInputs(); - } - }; - - /** - * Inserts node content at the caret position - * - * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location - */ - var emulateUserAgentBehaviour = function emulateUserAgentBehaviour(node) { - - var newNode; - - if (node.childElementCount) { - - newNode = document.createDocumentFragment(); - - node.childNodes.forEach(function (current) { - - if (!editor.core.isDomNode(current) && current.data.trim() === '') { - - return; - } - - newNode.appendChild(current.cloneNode(true)); - }); - } else { - - newNode = document.createTextNode(node.textContent); - } - - editor.caret.insertNode(newNode); - }; - - return paste; - }({}); + // module.exports = (function (core) { + // + // let editor = codex.editor; + // + // /** + // * @public + // * + // * Editor preparing method + // * @return Promise + // */ + // core.prepare = function (userSettings) { + // + // return new Promise(function (resolve, reject) { + // + // if ( userSettings ) { + // + // editor.settings.tools = userSettings.tools || editor.settings.tools; + // + // } + // + // if (userSettings.data) { + // + // editor.state.blocks = userSettings.data; + // + // } + // + // if (userSettings.initialBlockPlugin) { + // + // editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin; + // + // } + // + // if (userSettings.sanitizer) { + // + // editor.settings.sanitizer = userSettings.sanitizer; + // + // } + // + // editor.hideToolbar = userSettings.hideToolbar; + // + // editor.settings.placeholder = userSettings.placeholder || ''; + // + // editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId); + // + // if (typeof editor.nodes.holder === undefined || editor.nodes.holder === null) { + // + // reject(Error("Holder wasn't found by ID: #" + userSettings.holderId)); + // + // } else { + // + // resolve(); + // + // } + // + // }); + // + // }; + // + // /** + // * Logging method + // * @param type = ['log', 'info', 'warn'] + // */ + // core.log = function (msg, type, arg) { + // + // type = type || 'log'; + // + // if (!arg) { + // + // arg = msg || 'undefined'; + // msg = '[codex-editor]: %o'; + // + // } else { + // + // msg = '[codex-editor]: ' + msg; + // + // } + // + // try{ + // + // if ( 'console' in window && window.console[ type ] ) { + // + // if ( arg ) window.console[ type ]( msg, arg ); + // else window.console[ type ]( msg ); + // + // } + // + // }catch(e) {} + // + // }; + // + // /** + // * @protected + // * + // * Helper for insert one element after another + // */ + // core.insertAfter = function (target, element) { + // + // target.parentNode.insertBefore(element, target.nextSibling); + // + // }; + // + // /** + // * @const + // * + // * Readable DOM-node types map + // */ + // core.nodeTypes = { + // TAG : 1, + // TEXT : 3, + // COMMENT : 8, + // DOCUMENT_FRAGMENT: 11 + // }; + // + // /** + // * @const + // * Readable keys map + // */ + // 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 }; + // + // /** + // * @protected + // * + // * Check object for DOM node + // */ + // core.isDomNode = function (el) { + // + // return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG; + // + // }; + // + // /** + // * Checks passed object for emptiness + // * @require ES5 - Object.keys + // * @param {object} + // */ + // core.isEmpty = function ( obj ) { + // + // return Object.keys(obj).length === 0; + // + // }; + // + // /** + // * Native Ajax + // * @param {String} settings.url - request URL + // * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks + // * @param {function} settings.success + // * @param {function} settings.progress + // */ + // core.ajax = function (settings) { + // + // if (!settings || !settings.url) { + // + // return; + // + // } + // + // var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'), + // encodedString, + // isFormData, + // prop; + // + // + // settings.async = true; + // settings.type = settings.type || 'GET'; + // settings.data = settings.data || ''; + // settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8'; + // + // if (settings.type == 'GET' && settings.data) { + // + // settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data; + // + // } else { + // + // encodedString = ''; + // for(prop in settings.data) { + // + // encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&'); + // + // } + // + // } + // + // if (settings.withCredentials) { + // + // XMLHTTP.withCredentials = true; + // + // } + // + // /** + // * Value returned in beforeSend funtion will be passed as context to the other response callbacks + // * If beforeSend returns false, AJAX will be blocked + // */ + // let responseContext, + // beforeSendResult; + // + // if (typeof settings.beforeSend === 'function') { + // + // beforeSendResult = settings.beforeSend.call(); + // + // if (beforeSendResult === false) { + // + // return; + // + // } + // + // } + // + // XMLHTTP.open( settings.type, settings.url, settings.async ); + // + // /** + // * If we send FormData, we need no content-type header + // */ + // isFormData = isFormData_(settings.data); + // + // if (!isFormData) { + // + // if (settings.type !== 'POST') { + // + // XMLHTTP.setRequestHeader('Content-type', settings['content-type']); + // + // } else { + // + // XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); + // + // } + // + // } + // + // XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + // + // responseContext = beforeSendResult || XMLHTTP; + // + // if (typeof settings.progress === 'function') { + // + // XMLHTTP.upload.onprogress = settings.progress.bind(responseContext); + // + // } + // + // XMLHTTP.onreadystatechange = function () { + // + // if (XMLHTTP.readyState === 4) { + // + // if (XMLHTTP.status === 200) { + // + // if (typeof settings.success === 'function') { + // + // settings.success.call(responseContext, XMLHTTP.responseText); + // + // } + // + // } else { + // + // if (typeof settings.error === 'function') { + // + // settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status); + // + // } + // + // } + // + // } + // + // }; + // + // if (isFormData) { + // + // // Sending FormData + // XMLHTTP.send(settings.data); + // + // } else { + // + // // POST requests + // XMLHTTP.send(encodedString); + // + // } + // + // return XMLHTTP; + // + // }; + // + // /** + // * Appends script to head of document + // * @return Promise + // */ + // core.importScript = function (scriptPath, instanceName) { + // + // return new Promise(function (resolve, reject) { + // + // let script; + // + // /** Script is already loaded */ + // if ( !instanceName ) { + // + // reject('Instance name is missed'); + // + // } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) { + // + // resolve(scriptPath); + // + // } + // + // script = document.createElement('SCRIPT'); + // script.async = true; + // script.defer = true; + // script.id = editor.scriptPrefix + instanceName; + // + // script.onload = function () { + // + // resolve(scriptPath); + // + // }; + // + // script.onerror = function () { + // + // reject(scriptPath); + // + // }; + // + // script.src = scriptPath; + // document.head.appendChild(script); + // + // }); + // + // }; + // + // /** + // * Function for checking is it FormData object to send. + // * @param {Object} object to check + // * @return boolean + // */ + // var isFormData_ = function (object) { + // + // return object instanceof FormData; + // + // }; + // + // /** + // * Check block + // * @param target + // * @description Checks target is it native input + // */ + // core.isNativeInput = function (target) { + // + // var nativeInputAreas = ['INPUT', 'TEXTAREA']; + // + // return nativeInputAreas.indexOf(target.tagName) != -1; + // + // }; + // + // /** + // * Check if block is empty + // * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME + // * + // * @param block + // * @returns {boolean} + // */ + // core.isBlockEmpty = function (block) { + // + // const EXCEPTION_TAGS = ['IMG', 'IFRAME']; + // + // var nativeInputs = block.querySelectorAll('textarea, input'), + // nativeInputsAreEmpty = true, + // textContentIsEmpty = !block.textContent.trim(); + // + // Array.prototype.forEach.call(nativeInputs, function (input) { + // + // if (input.type == 'textarea' || input.type == 'text') { + // + // nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim(); + // + // } + // + // }); + // + // return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName); + // + // }; + // + // + // return core; + // + // })({}); /***/ }) -/******/ ]); + +/******/ }); //# sourceMappingURL=codex-editor.js.map \ No newline at end of file diff --git a/codex-editor.js.map b/codex-editor.js.map index 4c3453e3..7d47ba7b 100644 --- a/codex-editor.js.map +++ b/codex-editor.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap 54f529243ac7b12e246d","webpack:///./codex.js","webpack:///./modules/core.js","webpack:///./modules/tools.js","webpack:///./modules/transport.js","webpack:///./modules/renderer.js","webpack:///./modules/saver.js","webpack:///./modules/content.js","webpack:///./modules/toolbar/toolbar.js","webpack:///./modules/toolbar/settings.js","webpack:///./modules/toolbar/inline.js","webpack:///./modules/toolbar/toolbox.js","webpack:///./modules/callbacks.js","webpack:///./modules/draw.js","webpack:///./modules/caret.js","webpack:///./modules/notifications.js","webpack:///./modules/parser.js","webpack:///./modules/sanitizer.js","webpack:///./~/html-janitor/src/html-janitor.js","webpack:///./modules/listeners.js","webpack:///./modules/destroyer.js","webpack:///./modules/paste.js"],"names":["module","exports","config","configuration","instances","modules","modulePath","init","path","core","require","tools","transport","renderer","saver","content","toolbar","callbacks","draw","caret","notifications","parser","sanitizer","listeners","destroyer","paste","console","log","editor","prepare","userSettings","Promise","resolve","reject","settings","data","state","blocks","initialBlockPlugin","hideToolbar","placeholder","nodes","holder","document","getElementById","holderId","undefined","Error","msg","type","arg","window","e","insertAfter","target","element","parentNode","insertBefore","nextSibling","nodeTypes","TAG","TEXT","COMMENT","DOCUMENT_FRAGMENT","keys","BACKSPACE","TAB","ENTER","SHIFT","CTRL","ALT","ESC","SPACE","LEFT","UP","DOWN","RIGHT","DELETE","META","isDomNode","el","nodeType","isEmpty","obj","Object","length","ajax","url","XMLHTTP","XMLHttpRequest","ActiveXObject","encodedString","isFormData","prop","async","test","encodeURIComponent","withCredentials","responseContext","beforeSendResult","beforeSend","call","open","isFormData_","setRequestHeader","progress","upload","onprogress","bind","onreadystatechange","readyState","status","success","responseText","error","send","importScript","scriptPath","instanceName","script","scriptPrefix","createElement","defer","id","onload","onerror","src","head","appendChild","object","FormData","isNativeInput","nativeInputAreas","indexOf","tagName","isBlockEmpty","block","EXCEPTION_TAGS","nativeInputs","querySelectorAll","nativeInputsAreEmpty","textContentIsEmpty","textContent","trim","Array","prototype","forEach","input","value","includes","codex","resolve_","reject_","then","pluginsRequiresPreparation","allPlugins","pluginName","plugin","push","waitAllPluginsPreparation_","catch","plugins","allPluginsProcessed__","reduce","previousValue","iteration","pluginIsReady__","callPluginsPrepareMethod_","available","loadingMessage","currentRequest","arguments","node","add","fileSelected","clearInput","i","files","formData","multiple","append","name","selectAndUpload","args","setAttribute","accept","click","abort","makeBlocksFromData","items","ui","addInitialBlock","appendBlocks","nodeSequence","index","appendNodeAtIndex","getNodeAsync","createBlockFromData","blockData","insertBlock","blocksList","tool","position","toolData","render","unavailableBlock","innerHTML","dataset","inputPosition","stretched","isStretched","save","html","redactor","jsonOutput","saveBlocks","childNodes","getBlockData","all","makeOutput","saveBlockData","validateBlockData","blockContent","pluginsContent","validate","result","savedData","filter","map","time","Date","version","currentNode","editorAreaHightlighted","sync","markBlock","classList","className","BLOCK_HIGHLIGHTED","clearMark","remove","getFirstLevelBlock","body","contains","BLOCK_CLASSNAME","workingNodeChanged","targetNode","replaceBlock","targetBlock","newBlock","replaceChild","addBlockHandlers","saveInputs","needPlaceCaret","workingBlock","newBlockContent","blockType","composeNewBlock_","currentInputIndex","getCurrentInputIndex","editableElement","querySelector","emptyText","createTextNode","set","move","showPlusButton","inputs","setTimeout","setToNextBlock","switchBlock","blockToReplace","newBlockComposed","getDeepestTextNodeFromPosition","blockChilds","text","removeChild","lookingFromStart","BLOCK_CONTENT","BLOCK_STRETCHED","getRange","selection","getSelection","getRangeAt","splitBlock","inputIndex","anchorNode","anchorNodeText","caretOffset","anchorOffset","textBeforeCaret","textNodeBeforeCaret","textAfterCaret","textNodeAfterCaret","currentBlock","substring","previousChilds","nextChilds","reachedCurrent","child","previousChildsLength","nextChildsLength","newNode","NEW_BLOCK_TYPE","mergeBlocks","targetInputIndex","targetInput","currentInputContent","isLastNode","allChecked","allSiblingsEmpty_","sibling","wrapTextWithParagraphs","htmlData","plainData","wrapPlainTextWithParagraphs","wrapper","newWrapper","paragraph","firstLevelBlocks","blockTyped","cloneNode","plainText","split","join","getEditableParent","contentEditable","clear","load","articleData","currentContent","assign","concat","inline","toolbox","defaultToolbarHeight","defaultOffset","opened","current","toolType","makeSettings","showSettingsButton","close","button","toolbarButtons","toggle","hidePlusButton","plusButton","newYCoordinate","offsetTop","style","transform","Math","floor","hideRemoveActions","setting","actions","settingsBlock","pluginSettings","blockSettings","makeRemoveBlockButton","removeBlockWrapper","settingButton","actionWrapper","confirmAction","cancelAction","removeButtonClicked","confirmRemovingRequest","cancelRemovingRequest","action","showRemoveActions","firstLevelBlocksCount","buttonsOpened","actionsOpened","wrappersOffset","storedSelection","show","showInlineToolbar","selectedText","getSelectionText","inlineToolbar","showButtons","getWrappersOffset","coords","getSelectionCoords","newCoordinateX","newCoordinateY","offsetHeight","x","left","y","scrollY","top","closeButtons","closeAction","toolClicked","event","createLinkAction","defaultToolAction","buttons","hightlight","offset","getOffset","_x","_y","isNaN","offsetLeft","clientLeft","clientTop","offsetParent","sel","range","createRange","collapse","boundingLeft","boundingTop","rangeCount","cloneRange","getClientRects","rect","toString","showActions","inlineToolbarAnchorInputKeydown_","keyCode","editable","restoreSelection","setAnchor","preventDefault","stopImmediatePropagation","clearRange","isActive","isLinkActive","saveSelection","inputForLink","focus","dataType","execCommand","containerEl","preSelectionRange","start","selectNodeContents","setEnd","startContainer","startOffset","end","savedSel","charIndex","setStart","nodeStack","foundStart","stop","nextCharIndex","pop","removeAllRanges","addRange","queryCommandState","setButtonHighlighted","removeButtonsHighLight","tag","icon","openedOnBlock","leaf","currentTool","barButtons","nextToolIndex","toolToSelect","visibleTool","displayInToolbox","UNREPLACEBLE_TOOLS","workingNode","appendCallback","setToBlock","globalKeydown","enterKeyPressed_","redactorKeyDown","tabKeyPressedOnRedactorsZone_","enterKeyPressedOnRedactorsZone_","escapeKeyPressedOnRedactorsZone_","defaultKeyPressedOnRedactorsZone_","globalKeyup","arrowKeyPressed_","enterPressedOnBlock_","saveCurrentInputIndex","isEnterPressedOnToolbar","enableLineBreaks","stopPropagation","shiftKey","currentSelection","currentSelectedNode","caretAtTheEndOfText","atTheEnd","isTextNodeHasParentBetweenContenteditable","callback","enterPressedOnBlock","islastNode","redactorClicked","detectWhenClickedOnFirstLevelBlockArea_","firstLevelBlock","indexOfLastInput","inputIsEmpty","currentNodeType","isInitialType","flag","toolbarButtonClicked","plusButtonClicked","blockKeydown","blockRightOrDownArrowPressed_","backspacePressed_","blockLeftOrUpArrowPressed_","focusedNode","focusedNodeHolder","editableElementIndex","caretInLastChild","lastChild","deepestTextnode","caretInFirstChild","caretAtTheBeginning","firstChild","setToPreviousBlock","selectionLength","endOffset","atStart","showSettingsButtonClicked","currentToolType","ceBlock","bar","toolbarContent","inlineToolbarButtons","inlineToolbarActions","blockButtons","defaultSettings","div","pluginsSettings","settingsButton","toggler","toolbarButton","classname","toolIcon","toolTitle","toolbarButtonInline","properties","focusedNodeIndex","childs","nodeToSet","nextInput","emptyTextElement","previousInput","lastChildNode","lengthOfLastChildNode","pluginsRender","isFirstNode","isOffsetZero","insertNode","lastNode","deleteContents","setStartAfter","queue","addToQueue","splice","createHolder","errorThrown","errorMsg","notification","message","constructorSettings","cancel","confirm","inputField","confirmHandler","cancelHandler","create","okBtn","cancelBtn","okMsg","cancelMsg","insertPastedContent","isFirstLevelBlock","janitor","Config","CUSTOM","BASIC","tags","p","a","href","rel","init_","userCustomConfig","clean","dirtyString","customConfig","janitorInstance","allListeners","search","byElement","context","listenersOnElement","listener","byType","eventType","listenersWithType","byHandler","handler","listenersWithHandler","one","isCapture","addEventListener","alreadyAddedListener","removeEventListener","existingListeners","removeAll","get","removeNodes","destroyPlugins","destroy","destroyScripts","scripts","getElementsByTagName","patterns","renderOnPastePatterns","isArray","pattern","pasted","clipBoardData","clipboardData","getData","analize","string","execArray","regex","exec","match","pasteToNewBlock_","blockPasteCallback","needsToHandlePasteEvent","paragraphs","cleanData","wrappedData","emulateUserAgentBehaviour","insertPastedParagraphs","editableParent","childElementCount","createDocumentFragment"],"mappings":";;AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;;;;;;;ACtCA;;;;;;AAMAA,QAAOC,OAAP;AAAA;AAAA;;;AAEI;AAFJ,6BAGyB;;AAEjB,oBAAO,SAAP;AAEH;;AAED;;AATJ;AAAA;AAAA,6BAU8B;;AAEtB,oBAAO,aAAP;AAEH;;AAED;;;;;;;AAhBJ;;AAsBI,0BAAYC,MAAZ,EAAoB;;AAEhB;;AAFgB;;AAIhB,cAAKC,aAAL,GAAqBD,MAArB;AACA,cAAKE,SAAL,GAAiB,EAAjB;;AAEA,aAAIC,UAAU,CACN,MADM,EAEN,OAFM,EAGN,WAHM,EAIN,UAJM,EAKN,OALM,EAMN,SANM,EAON,iBAPM,EAQN,WARM,EASN,MATM,EAUN,OAVM,EAWN,eAXM,EAYN,QAZM,EAaN,WAbM,EAcN,WAdM,EAeN,WAfM,EAgBN,OAhBM,CAAd;AAAA,aAkBIC,aAAa,YAlBjB;;AAoBA,cAAKC,IAAL,CAAUD,UAAV;AAEH;;AAED;;;;;;;;;;AArDJ;AAAA;AAAA,8BA6DSE,IA7DT,EA6De;;AAEP,iBAAIC,OAAkB,mBAAAC,CAAQ,CAAR,CAAtB;AAAA,iBACIC,QAAkB,mBAAAD,CAAQ,CAAR,CADtB;AAAA,iBAEIE,YAAkB,mBAAAF,CAAQ,CAAR,CAFtB;AAAA,iBAGIG,WAAkB,mBAAAH,CAAQ,CAAR,CAHtB;AAAA,iBAIII,QAAkB,mBAAAJ,CAAQ,CAAR,CAJtB;AAAA,iBAKIK,UAAkB,mBAAAL,CAAQ,CAAR,CALtB;AAAA,iBAMIM,UAAkB,mBAAAN,CAAQ,CAAR,CANtB;AAAA,iBAOIO,YAAkB,mBAAAP,CAAQ,EAAR,CAPtB;AAAA,iBAQIQ,OAAkB,mBAAAR,CAAQ,EAAR,CARtB;AAAA,iBASIS,QAAkB,mBAAAT,CAAQ,EAAR,CATtB;AAAA,iBAUIU,gBAAkB,mBAAAV,CAAQ,EAAR,CAVtB;AAAA,iBAWIW,SAAkB,mBAAAX,CAAQ,EAAR,CAXtB;AAAA,iBAYIY,YAAkB,mBAAAZ,CAAQ,EAAR,CAZtB;AAAA,iBAaIa,YAAkB,mBAAAb,CAAQ,EAAR,CAbtB;AAAA,iBAcIc,YAAkB,mBAAAd,CAAQ,EAAR,CAdtB;AAAA,iBAeIe,QAAkB,mBAAAf,CAAQ,EAAR,CAftB;;AAiBA,kBAAKN,SAAL,CAAe,MAAf,IAAyBK,IAAzB;AACA,kBAAKL,SAAL,CAAe,OAAf,IAA0BO,KAA1B;;AAGAe,qBAAQC,GAAR,CAAY,OAAZ,EAAqB,IAArB;AAEH;AAtFL;;AAAA;AAAA;AA0FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,W;;;;;;;;;;AC1OA;;;;;;;AAOA3B,QAAOC,OAAP,GAAkB,UAAUQ,IAAV,EAAgB;;AAE9B,SAAImB,SAAS,CAAb;;AAEA;;;;;;AAMAnB,UAAKoB,OAAL,GAAe,UAAUC,YAAV,EAAwB;;AAEnC,gBAAO,IAAIC,OAAJ,CAAY,UAAUC,OAAV,EAAmBC,M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kBL,MAAMI,YAAN,CAAtB;;AAEA,gBAAOC,gBAAgBH,KAAhB,CAAsBC,WAAtB,CAAP;AAEH,MAND;;AAQA,YAAOvjB,SAAP;AAEH,EA3EgB,CA2Ed,EA3Ec,CAAjB,C;;;;;;ACJA;AACA;AACA;AACA,IAAG;AACH;AACA,IAAG;AACH;AACA;AACA,EAAC;;AAED;AACA,cAAa,OAAO;AACpB,cAAa,QAAQ;AACrB;AACA;;AAEA;AACA;;AAEA;AACA,yBAAwB,iCAAiC,EAAE;AAC3D,8BAA6B,uEAAuE,EAAE;;AAEtG;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,iBAAgB,QAAQ;;AAExB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,gEAA+D;AAC/D;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,sBAAqB,4BAA4B;AACjD;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAK;AACL;AACA,MAAK;AACL;AACA,MAAK;AACL;AACA,MAAK;AACL;AACA;;AAEA;AACA;;AAEA;;AAEA,EAAC;;;;;;;;;ACxLD;;;;;;;AAOA;;;AAGAtB,QAAOC,OAAP,GAAiB,UAAUsB,SAAV,EAAqB;;AAElC,SAAIyjB,eAAe,EAAnB;;AAEA;;;;;;;AAOAzjB,eAAU0j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","file":"codex-editor.js","sourcesContent":[" \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 54f529243ac7b12e246d","/**\n *\n * Codex Editor\n *\n * @author Codex Team\n */\nmodule.exports = class CodexEditor {\n\n /** Editor version */\n static get version() {\n\n return VERSION;\n\n }\n\n /** Editor script prefixes */\n static get scriptPrefix() {\n\n return 'cdx-script-';\n\n }\n\n /**\n * @param config\n *\n * @property this.configuration - editor instance configuration\n * @property this.instances - editor module instances\n */\n constructor(config) {\n\n 'use strict';\n\n this.configuration = config;\n this.instances = [];\n\n let modules = [\n 'core',\n 'tools',\n 'transport',\n 'renderer',\n 'saver',\n 'content',\n 'toolbar/toolbar',\n 'callbacks',\n 'draw',\n 'caret',\n 'notifications',\n 'parser',\n 'sanitizer',\n 'listeners',\n 'destroyer',\n 'paste'\n ],\n modulePath = './modules/';\n\n this.init(modulePath);\n\n }\n\n /**\n * Initializes modules:\n * First: requiring modules from path\n * Second: memorizing the instances\n *\n * @param {String} module name\n * @param {String} module path\n */\n init(path) {\n\n let core = require('./modules/core'),\n tools = require('./modules/tools'),\n transport = require('./modules/transport'),\n renderer = require('./modules/renderer'),\n saver = require('./modules/saver'),\n content = require('./modules/content'),\n toolbar = require('./modules/toolbar/toolbar'),\n callbacks = require('./modules/callbacks'),\n draw = require('./modules/draw'),\n caret = require('./modules/caret'),\n notifications = require('./modules/notifications'),\n parser = require('./modules/parser'),\n sanitizer = require('./modules/sanitizer'),\n listeners = require('./modules/listeners'),\n destroyer = require('./modules/destroyer'),\n paste = require('./modules/paste');\n\n this.instances['core'] = core;\n this.instances['tools'] = tools;\n\n\n console.log('Class', this);\n\n }\n\n\n};\n// module.exports = (function (editor) {\n//\n// 'use strict';\n//\n// editor.version = VERSION;\n// editor.scriptPrefix = 'cdx-script-';\n//\n// var init = function () {\n//\n// editor.core = require('./modules/core');\n// editor.tools = require('./modules/tools');\n// editor.ui = require('./modules/ui');\n// editor.transport = require('./modules/transport');\n// editor.renderer = require('./modules/renderer');\n// editor.saver = require('./modules/saver');\n// editor.content = require('./modules/content');\n// editor.toolbar = require('./modules/toolbar/toolbar');\n// editor.callback = require('./modules/callbacks');\n// editor.draw = require('./modules/draw');\n// editor.caret = require('./modules/caret');\n// editor.notifications = require('./modules/notifications');\n// editor.parser = require('./modules/parser');\n// editor.sanitizer = require('./modules/sanitizer');\n// editor.listeners = require('./modules/listeners');\n// editor.destroyer = require('./modules/destroyer');\n// editor.paste = require('./modules/paste');\n//\n// };\n//\n// /**\n// * @public\n// * holds initial settings\n// */\n// editor.settings = {\n// tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n// holderId : 'codex-editor',\n//\n// // Type of block showing on empty editor\n// initialBlockPlugin: 'paragraph'\n// };\n//\n// /**\n// * public\n// *\n// * Static nodes\n// */\n// editor.nodes = {\n// holder : null,\n// wrapper : null,\n// toolbar : null,\n// inlineToolbar : {\n// wrapper : null,\n// buttons : null,\n// actions : null\n// },\n// toolbox : null,\n// notifications : null,\n// plusButton : null,\n// showSettingsButton: null,\n// showTrashButton : null,\n// blockSettings : null,\n// pluginSettings : null,\n// defaultSettings : null,\n// toolbarButtons : {}, // { type : DomEl, ... }\n// redactor : null\n// };\n//\n// /**\n// * @public\n// *\n// * Output state\n// */\n// editor.state = {\n// jsonOutput : [],\n// blocks : [],\n// inputs : []\n// };\n//\n// /**\n// * @public\n// * Editor plugins\n// */\n// editor.tools = {};\n//\n// /**\n// * Initialization\n// * @uses Promise cEditor.core.prepare\n// * @param {Object} userSettings\n// * @param {Array} userSettings.tools list of plugins\n// * @param {String} userSettings.holderId Element's id to append editor\n// *\n// * Load user defined tools\n// * Tools must contain this important objects :\n// * @param {String} type - this is a type of plugin. It can be used as plugin name\n// * @param {String} iconClassname - this a icon in toolbar\n// * @param {Object} make - what should plugin do, when it is clicked\n// * @param {Object} appendCallback - callback after clicking\n// * @param {Element} settings - what settings does it have\n// * @param {Object} render - plugin get JSON, and should return HTML\n// * @param {Object} save - plugin gets HTML content, returns JSON\n// * @param {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\n// * @param {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\n// *\n// * @example\n// * - type : 'header',\n// * - iconClassname : 'ce-icon-header',\n// * - make : headerTool.make,\n// * - appendCallback : headerTool.appendCallback,\n// * - settings : headerTool.makeSettings(),\n// * - render : headerTool.render,\n// * - save : headerTool.save,\n// * - displayInToolbox : true,\n// * - enableLineBreaks : false\n// */\n// editor.start = function (userSettings) {\n//\n// init();\n//\n// editor.core.prepare(userSettings)\n//\n// // If all ok, make UI, bind events and parse initial-content\n// .then(editor.ui.prepare)\n// .then(editor.tools.prepare)\n// .then(editor.sanitizer.prepare)\n// .then(editor.paste.prepare)\n// .then(editor.transport.prepare)\n// .then(editor.renderer.makeBlocksFromData)\n// .then(editor.ui.saveInputs)\n// .catch(function (error) {\n//\n// editor.core.log('Initialization failed with error: %o', 'warn', error);\n//\n// });\n//\n// };\n//\n// return editor;\n//\n// })({});\n\n\n\n// WEBPACK FOOTER //\n// ./codex.js","/**\n * Codex Editor Core\n *\n * @author Codex Team\n * @version 1.1.3\n */\n\nmodule.exports = (function (core) {\n\n let editor = 1;\n\n /**\n * @public\n *\n * Editor preparing method\n * @return Promise\n */\n core.prepare = function (userSettings) {\n\n return new Promise(function (resolve, reject) {\n\n if ( userSettings ) {\n\n editor.settings.tools = userSettings.tools || editor.settings.tools;\n\n }\n\n if (userSettings.data) {\n\n editor.state.blocks = userSettings.data;\n\n }\n\n if (userSettings.initialBlockPlugin) {\n\n editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\n\n }\n\n if (userSettings.sanitizer) {\n\n editor.settings.sanitizer = userSettings.sanitizer;\n\n }\n\n editor.hideToolbar = userSettings.hideToolbar;\n\n editor.settings.placeholder = userSettings.placeholder || '';\n\n editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId);\n\n if (typeof editor.nodes.holder === undefined || editor.nodes.holder === null) {\n\n reject(Error(\"Holder wasn't found by ID: #\" + userSettings.holderId));\n\n } else {\n\n resolve();\n\n }\n\n });\n\n };\n\n /**\n * Logging method\n * @param type = ['log', 'info', 'warn']\n */\n core.log = function (msg, type, arg) {\n\n type = type || 'log';\n\n if (!arg) {\n\n arg = msg || 'undefined';\n msg = '[codex-editor]: %o';\n\n } else {\n\n msg = '[codex-editor]: ' + msg;\n\n }\n\n try{\n\n if ( 'console' in window && window.console[ type ] ) {\n\n if ( arg ) window.console[ type ]( msg, arg );\n else window.console[ type ]( msg );\n\n }\n\n }catch(e) {}\n\n };\n\n /**\n * @protected\n *\n * Helper for insert one element after another\n */\n core.insertAfter = function (target, element) {\n\n target.parentNode.insertBefore(element, target.nextSibling);\n\n };\n\n /**\n * @const\n *\n * Readable DOM-node types map\n */\n core.nodeTypes = {\n TAG : 1,\n TEXT : 3,\n COMMENT : 8,\n DOCUMENT_FRAGMENT: 11\n };\n\n /**\n * @const\n * Readable keys map\n */\n core.keys = { BACKSPACE: 8, TAB: 9, ENTER: 13, SHIFT: 16, CTRL: 17, ALT: 18, ESC: 27, SPACE: 32, LEFT: 37, UP: 38, DOWN: 40, RIGHT: 39, DELETE: 46, META: 91 };\n\n /**\n * @protected\n *\n * Check object for DOM node\n */\n core.isDomNode = function (el) {\n\n return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG;\n\n };\n\n /**\n * Checks passed object for emptiness\n * @require ES5 - Object.keys\n * @param {object}\n */\n core.isEmpty = function ( obj ) {\n\n return Object.keys(obj).length === 0;\n\n };\n\n /**\n * Native Ajax\n * @param {String} settings.url - request URL\n * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks\n * @param {function} settings.success\n * @param {function} settings.progress\n */\n core.ajax = function (settings) {\n\n if (!settings || !settings.url) {\n\n return;\n\n }\n\n var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\n encodedString,\n isFormData,\n prop;\n\n\n settings.async = true;\n settings.type = settings.type || 'GET';\n settings.data = settings.data || '';\n settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8';\n\n if (settings.type == 'GET' && settings.data) {\n\n settings.url = /\\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data;\n\n } else {\n\n encodedString = '';\n for(prop in settings.data) {\n\n encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&');\n\n }\n\n }\n\n if (settings.withCredentials) {\n\n XMLHTTP.withCredentials = true;\n\n }\n\n /**\n * Value returned in beforeSend funtion will be passed as context to the other response callbacks\n * If beforeSend returns false, AJAX will be blocked\n */\n let responseContext,\n beforeSendResult;\n\n if (typeof settings.beforeSend === 'function') {\n\n beforeSendResult = settings.beforeSend.call();\n\n if (beforeSendResult === false) {\n\n return;\n\n }\n\n }\n\n XMLHTTP.open( settings.type, settings.url, settings.async );\n\n /**\n * If we send FormData, we need no content-type header\n */\n isFormData = isFormData_(settings.data);\n\n if (!isFormData) {\n\n if (settings.type !== 'POST') {\n\n XMLHTTP.setRequestHeader('Content-type', settings['content-type']);\n\n } else {\n\n XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n\n }\n\n }\n\n XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n\n responseContext = beforeSendResult || XMLHTTP;\n\n if (typeof settings.progress === 'function') {\n\n XMLHTTP.upload.onprogress = settings.progress.bind(responseContext);\n\n }\n\n XMLHTTP.onreadystatechange = function () {\n\n if (XMLHTTP.readyState === 4) {\n\n if (XMLHTTP.status === 200) {\n\n if (typeof settings.success === 'function') {\n\n settings.success.call(responseContext, XMLHTTP.responseText);\n\n }\n\n } else {\n\n if (typeof settings.error === 'function') {\n\n settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status);\n\n }\n\n }\n\n }\n\n };\n\n if (isFormData) {\n\n // Sending FormData\n XMLHTTP.send(settings.data);\n\n } else {\n\n // POST requests\n XMLHTTP.send(encodedString);\n\n }\n\n return XMLHTTP;\n\n };\n\n /**\n * Appends script to head of document\n * @return Promise\n */\n core.importScript = function (scriptPath, instanceName) {\n\n return new Promise(function (resolve, reject) {\n\n let script;\n\n /** Script is already loaded */\n if ( !instanceName ) {\n\n reject('Instance name is missed');\n\n } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) {\n\n resolve(scriptPath);\n\n }\n\n script = document.createElement('SCRIPT');\n script.async = true;\n script.defer = true;\n script.id = editor.scriptPrefix + instanceName;\n\n script.onload = function () {\n\n resolve(scriptPath);\n\n };\n\n script.onerror = function () {\n\n reject(scriptPath);\n\n };\n\n script.src = scriptPath;\n document.head.appendChild(script);\n\n });\n\n };\n\n /**\n * Function for checking is it FormData object to send.\n * @param {Object} object to check\n * @return boolean\n */\n var isFormData_ = function (object) {\n\n return object instanceof FormData;\n\n };\n\n /**\n * Check block\n * @param target\n * @description Checks target is it native input\n */\n core.isNativeInput = function (target) {\n\n var nativeInputAreas = ['INPUT', 'TEXTAREA'];\n\n return nativeInputAreas.indexOf(target.tagName) != -1;\n\n };\n\n /**\n * Check if block is empty\n * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME\n *\n * @param block\n * @returns {boolean}\n */\n core.isBlockEmpty = function (block) {\n\n const EXCEPTION_TAGS = ['IMG', 'IFRAME'];\n\n var nativeInputs = block.querySelectorAll('textarea, input'),\n nativeInputsAreEmpty = true,\n textContentIsEmpty = !block.textContent.trim();\n\n Array.prototype.forEach.call(nativeInputs, function (input) {\n\n if (input.type == 'textarea' || input.type == 'text') {\n\n nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim();\n\n }\n\n });\n\n return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName);\n\n };\n\n\n return core;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/core.js","/**\n* Module working with plugins\n*/\nmodule.exports = (function () {\n\n let editor = codex.editor;\n\n /**\n * Initialize plugins before using\n * Ex. Load scripts or call some internal methods\n * @return Promise\n */\n function prepare() {\n\n return new Promise(function (resolve_, reject_) {\n\n Promise.resolve()\n\n /**\n * Compose a sequence of plugins that requires preparation\n */\n .then(function () {\n\n let pluginsRequiresPreparation = [],\n allPlugins = editor.tools;\n\n for ( let pluginName in allPlugins ) {\n\n let plugin = allPlugins[pluginName];\n\n if (plugin.prepare && typeof plugin.prepare != 'function' || !plugin.prepare) {\n\n continue;\n\n }\n\n pluginsRequiresPreparation.push(plugin);\n\n }\n\n /**\n * If no one passed plugins requires preparation, finish prepare() and go ahead\n */\n if (!pluginsRequiresPreparation.length) {\n\n resolve_();\n\n }\n\n return pluginsRequiresPreparation;\n\n })\n\n /** Wait plugins while they prepares */\n .then(waitAllPluginsPreparation_)\n\n .then(function () {\n\n editor.core.log('Plugins loaded', 'info');\n resolve_();\n\n }).catch(function (error) {\n\n reject_(error);\n\n });\n\n });\n\n }\n\n /**\n * @param {array} plugins - list of tools that requires preparation\n * @return {Promise} resolved while all plugins will be ready or failed\n */\n function waitAllPluginsPreparation_(plugins) {\n\n /**\n * @calls allPluginsProcessed__ when all plugins prepared or failed\n */\n return new Promise (function (allPluginsProcessed__) {\n\n /**\n * pluck each element from queue\n * First, send resolved Promise as previous value\n * Each plugins \"prepare\" method returns a Promise, that's why\n * reduce current element will not be able to continue while can't get\n * a resolved Promise\n *\n * If last plugin is \"prepared\" then go to the next stage of initialization\n */\n plugins.reduce(function (previousValue, plugin, iteration) {\n\n return previousValue.then(function () {\n\n /**\n * Wait till plugins prepared\n * @calls pluginIsReady__ when plugin is ready or failed\n */\n return new Promise ( function (pluginIsReady__) {\n\n callPluginsPrepareMethod_( plugin )\n\n .then( pluginIsReady__ )\n .then( function () {\n\n plugin.available = true;\n\n })\n\n .catch(function (error) {\n\n editor.core.log(`Plugin «${plugin.type}» was not loaded. Preparation failed because %o`, 'warn', error);\n plugin.available = false;\n plugin.loadingMessage = error;\n\n /** Go ahead even some plugin has problems */\n pluginIsReady__();\n\n })\n\n .then(function () {\n\n /** If last plugin has problems then just ignore and continue */\n if (iteration == plugins.length - 1) {\n\n allPluginsProcessed__();\n\n }\n\n });\n\n });\n\n });\n\n }, Promise.resolve() );\n\n });\n\n }\n\n var callPluginsPrepareMethod_ = function (plugin) {\n\n return plugin.prepare( plugin.config || {} );\n\n };\n\n return {\n prepare: prepare\n };\n\n}());\n\n\n// WEBPACK FOOTER //\n// ./modules/tools.js","/**\n *\n * Codex.Editor Transport Module\n *\n * @copyright 2017 Codex-Team\n * @version 1.2.0\n */\n\nmodule.exports = (function (transport) {\n\n let editor = codex.editor;\n\n\n /**\n * @private {Object} current XmlHttpRequest instance\n */\n var currentRequest = null;\n\n\n /**\n * @type {null} | {DOMElement} input - keeps input element in memory\n */\n transport.input = null;\n\n /**\n * @property {Object} arguments - keep plugin settings and defined callbacks\n */\n transport.arguments = null;\n\n /**\n * Prepares input element where will be files\n */\n transport.prepare = function () {\n\n let input = editor.draw.node( 'INPUT', '', { type : 'file' } );\n\n editor.listeners.add(input, 'change', editor.transport.fileSelected);\n editor.transport.input = input;\n\n };\n\n /** Clear input when files is uploaded */\n transport.clearInput = function () {\n\n /** Remove old input */\n transport.input = null;\n\n /** Prepare new one */\n transport.prepare();\n\n };\n\n /**\n * Callback for file selection\n * @param {Event} event\n */\n transport.fileSelected = function () {\n\n var input = this,\n i,\n files = input.files,\n formData = new FormData();\n\n if (editor.transport.arguments.multiple === true) {\n\n for ( i = 0; i < files.length; i++) {\n\n formData.append('files[]', files[i], files[i].name);\n\n }\n\n } else {\n\n formData.append('files', files[0], files[0].name);\n\n }\n\n currentRequest = editor.core.ajax({\n type : 'POST',\n data : formData,\n url : editor.transport.arguments.url,\n beforeSend : editor.transport.arguments.beforeSend,\n success : editor.transport.arguments.success,\n error : editor.transport.arguments.error,\n progress : editor.transport.arguments.progress\n });\n\n /** Clear input */\n transport.clearInput();\n\n };\n\n /**\n * Use plugin callbacks\n * @protected\n *\n * @param {Object} args - can have :\n * @param {String} args.url - fetch URL\n * @param {Function} args.beforeSend - function calls before sending ajax\n * @param {Function} args.success - success callback\n * @param {Function} args.error - on error handler\n * @param {Function} args.progress - xhr onprogress handler\n * @param {Boolean} args.multiple - allow select several files\n * @param {String} args.accept - adds accept attribute\n */\n transport.selectAndUpload = function (args) {\n\n transport.arguments = args;\n\n if ( args.multiple === true) {\n\n transport.input.setAttribute('multiple', 'multiple');\n\n }\n\n if ( args.accept ) {\n\n transport.input.setAttribute('accept', args.accept);\n\n }\n\n transport.input.click();\n\n };\n\n transport.abort = function () {\n\n currentRequest.abort();\n\n currentRequest = null;\n\n };\n\n return transport;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/transport.js","/**\n * Codex Editor Renderer Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (renderer) {\n\n let editor = codex.editor;\n\n /**\n * Asyncronously parses input JSON to redactor blocks\n */\n renderer.makeBlocksFromData = function () {\n\n /**\n * If redactor is empty, add first paragraph to start writing\n */\n if (editor.core.isEmpty(editor.state.blocks) || !editor.state.blocks.items.length) {\n\n editor.ui.addInitialBlock();\n return;\n\n }\n\n Promise.resolve()\n\n /** First, get JSON from state */\n .then(function () {\n\n return editor.state.blocks;\n\n })\n\n /** Then, start to iterate they */\n .then(editor.renderer.appendBlocks)\n\n /** Write log if something goes wrong */\n .catch(function (error) {\n\n editor.core.log('Error while parsing JSON: %o', 'error', error);\n\n });\n\n };\n\n /**\n * Parses JSON to blocks\n * @param {object} data\n * @return Primise -> nodeList\n */\n renderer.appendBlocks = function (data) {\n\n var blocks = data.items;\n\n /**\n * Sequence of one-by-one blocks appending\n * Uses to save blocks order after async-handler\n */\n var nodeSequence = Promise.resolve();\n\n for (var index = 0; index < blocks.length ; index++ ) {\n\n /** Add node to sequence at specified index */\n editor.renderer.appendNodeAtIndex(nodeSequence, blocks, index);\n\n }\n\n };\n\n /**\n * Append node at specified index\n */\n renderer.appendNodeAtIndex = function (nodeSequence, blocks, index) {\n\n /** We need to append node to sequence */\n nodeSequence\n\n /** first, get node async-aware */\n .then(function () {\n\n return editor.renderer.getNodeAsync(blocks, index);\n\n })\n\n /**\n * second, compose editor-block from JSON object\n */\n .then(editor.renderer.createBlockFromData)\n\n /**\n * now insert block to redactor\n */\n .then(function (blockData) {\n\n /**\n * blockData has 'block', 'type' and 'stretched' information\n */\n editor.content.insertBlock(blockData);\n\n /** Pass created block to next step */\n return blockData.block;\n\n })\n\n /** Log if something wrong with node */\n .catch(function (error) {\n\n editor.core.log('Node skipped while parsing because %o', 'error', error);\n\n });\n\n };\n\n /**\n * Asynchronously returns block data from blocksList by index\n * @return Promise to node\n */\n renderer.getNodeAsync = function (blocksList, index) {\n\n return Promise.resolve().then(function () {\n\n return {\n tool : blocksList[index],\n position : index\n };\n\n });\n\n };\n\n /**\n * Creates editor block by JSON-data\n *\n * @uses render method of each plugin\n *\n * @param {Object} toolData.tool\n * { header : {\n * text: '',\n * type: 'H3', ...\n * }\n * }\n * @param {Number} toolData.position - index in input-blocks array\n * @return {Object} with type and Element\n */\n renderer.createBlockFromData = function ( toolData ) {\n\n /** New parser */\n var block,\n tool = toolData.tool,\n pluginName = tool.type;\n\n /** Get first key of object that stores plugin name */\n // for (var pluginName in blockData) break;\n\n /** Check for plugin existance */\n if (!editor.tools[pluginName]) {\n\n throw Error(`Plugin «${pluginName}» not found`);\n\n }\n\n /** Check for plugin having render method */\n if (typeof editor.tools[pluginName].render != 'function') {\n\n throw Error(`Plugin «${pluginName}» must have «render» method`);\n\n }\n\n if ( editor.tools[pluginName].available === false ) {\n\n block = editor.draw.unavailableBlock();\n\n block.innerHTML = editor.tools[pluginName].loadingMessage;\n\n /**\n * Saver will extract data from initial block data by position in array\n */\n block.dataset.inputPosition = toolData.position;\n\n } else {\n\n /** New Parser */\n block = editor.tools[pluginName].render(tool.data);\n\n }\n\n /** is first-level block stretched */\n var stretched = editor.tools[pluginName].isStretched || false;\n\n /** Retrun type and block */\n return {\n type : pluginName,\n block : block,\n stretched : stretched\n };\n\n };\n\n return renderer;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/renderer.js","/**\n * Codex Editor Saver\n *\n * @author Codex Team\n * @version 1.1.0\n */\n\nmodule.exports = (function (saver) {\n\n let editor = codex.editor;\n\n /**\n * @public\n * Save blocks\n */\n saver.save = function () {\n\n /** Save html content of redactor to memory */\n editor.state.html = editor.nodes.redactor.innerHTML;\n\n /** Clean jsonOutput state */\n editor.state.jsonOutput = [];\n\n return saveBlocks(editor.nodes.redactor.childNodes);\n\n };\n\n /**\n * @private\n * Save each block data\n *\n * @param blocks\n * @returns {Promise.}\n */\n let saveBlocks = function (blocks) {\n\n let data = [];\n\n for(let index = 0; index < blocks.length; index++) {\n\n data.push(getBlockData(blocks[index]));\n\n }\n\n return Promise.all(data)\n .then(makeOutput)\n .catch(editor.core.log);\n\n };\n\n /** Save and validate block data */\n let getBlockData = function (block) {\n\n return saveBlockData(block)\n .then(validateBlockData)\n .catch(editor.core.log);\n\n };\n\n /**\n * @private\n * Call block`s plugin save method and return saved data\n *\n * @param block\n * @returns {Object}\n */\n let saveBlockData = function (block) {\n\n let pluginName = block.dataset.tool;\n\n /** Check for plugin existence */\n if (!editor.tools[pluginName]) {\n\n editor.core.log(`Plugin «${pluginName}» not found`, 'error');\n return {data: null, pluginName: null};\n\n }\n\n /** Check for plugin having save method */\n if (typeof editor.tools[pluginName].save !== 'function') {\n\n editor.core.log(`Plugin «${pluginName}» must have save method`, 'error');\n return {data: null, pluginName: null};\n\n }\n\n /** Result saver */\n let blockContent = block.childNodes[0],\n pluginsContent = blockContent.childNodes[0],\n position = pluginsContent.dataset.inputPosition;\n\n /** If plugin wasn't available then return data from cache */\n if ( editor.tools[pluginName].available === false ) {\n\n return Promise.resolve({data: codex.editor.state.blocks.items[position].data, pluginName});\n\n }\n\n return Promise.resolve(pluginsContent)\n .then(editor.tools[pluginName].save)\n .then(data => Object({data, pluginName}));\n\n };\n\n /**\n * Call plugin`s validate method. Return false if validation failed\n *\n * @param data\n * @param pluginName\n * @returns {Object|Boolean}\n */\n let validateBlockData = function ({data, pluginName}) {\n\n if (!data || !pluginName) {\n\n return false;\n\n }\n\n if (editor.tools[pluginName].validate) {\n\n let result = editor.tools[pluginName].validate(data);\n\n /**\n * Do not allow invalid data\n */\n if (!result) {\n\n return false;\n\n }\n\n }\n\n return {data, pluginName};\n\n\n };\n\n /**\n * Compile article output\n *\n * @param savedData\n * @returns {{time: number, version, items: (*|Array)}}\n */\n let makeOutput = function (savedData) {\n\n savedData = savedData.filter(blockData => blockData);\n\n let items = savedData.map(blockData => Object({type: blockData.pluginName, data: blockData.data}));\n\n editor.state.jsonOutput = items;\n\n return {\n id: editor.state.blocks.id || null,\n time: +new Date(),\n version: editor.version,\n items\n };\n\n };\n\n return saver;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/saver.js","/**\n * Codex Editor Content Module\n * Works with DOM\n *\n * @module Codex Editor content module\n *\n * @author Codex Team\n * @version 1.3.13\n *\n * @description Module works with Elements that have been appended to the main DOM\n */\n\nmodule.exports = (function (content) {\n\n let editor = codex.editor;\n\n /**\n * Links to current active block\n * @type {null | Element}\n */\n content.currentNode = null;\n\n /**\n * clicked in redactor area\n * @type {null | Boolean}\n */\n content.editorAreaHightlighted = null;\n\n /**\n * @deprecated\n * Synchronizes redactor with original textarea\n */\n content.sync = function () {\n\n editor.core.log('syncing...');\n\n /**\n * Save redactor content to editor.state\n */\n editor.state.html = editor.nodes.redactor.innerHTML;\n\n };\n\n /**\n * Appends background to the block\n *\n * @description add CSS class to highlight visually first-level block area\n */\n content.markBlock = function () {\n\n editor.content.currentNode.classList.add(editor.ui.className.BLOCK_HIGHLIGHTED);\n\n };\n\n /**\n * Clear background\n *\n * @description clears styles that highlights block\n */\n content.clearMark = function () {\n\n if (editor.content.currentNode) {\n\n editor.content.currentNode.classList.remove(editor.ui.className.BLOCK_HIGHLIGHTED);\n\n }\n\n };\n\n /**\n * Finds first-level block\n *\n * @param {Element} node - selected or clicked in redactors area node\n * @protected\n *\n * @description looks for first-level block.\n * gets parent while node is not first-level\n */\n content.getFirstLevelBlock = function (node) {\n\n if (!editor.core.isDomNode(node)) {\n\n node = node.parentNode;\n\n }\n\n if (node === editor.nodes.redactor || node === document.body) {\n\n return null;\n\n } else {\n\n while(!node.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\n\n node = node.parentNode;\n\n }\n\n return node;\n\n }\n\n };\n\n /**\n * Trigger this event when working node changed\n * @param {Element} targetNode - first-level of this node will be current\n * @protected\n *\n * @description If targetNode is first-level then we set it as current else we look for parents to find first-level\n */\n content.workingNodeChanged = function (targetNode) {\n\n /** Clear background from previous marked block before we change */\n editor.content.clearMark();\n\n if (!targetNode) {\n\n return;\n\n }\n\n content.currentNode = content.getFirstLevelBlock(targetNode);\n\n };\n\n /**\n * Replaces one redactor block with another\n * @protected\n * @param {Element} targetBlock - block to replace. Mostly currentNode.\n * @param {Element} newBlock\n * @param {string} newBlockType - type of new block; we need to store it to data-attribute\n *\n * [!] Function does not saves old block content.\n * You can get it manually and pass with newBlock.innerHTML\n */\n content.replaceBlock = function (targetBlock, newBlock) {\n\n if (!targetBlock || !newBlock) {\n\n editor.core.log('replaceBlock: missed params');\n return;\n\n }\n\n /** If target-block is not a frist-level block, then we iterate parents to find it */\n while(!targetBlock.classList.contains(editor.ui.className.BLOCK_CLASSNAME)) {\n\n targetBlock = targetBlock.parentNode;\n\n }\n\n /** Replacing */\n editor.nodes.redactor.replaceChild(newBlock, targetBlock);\n\n /**\n * Set new node as current\n */\n editor.content.workingNodeChanged(newBlock);\n\n /**\n * Add block handlers\n */\n editor.ui.addBlockHandlers(newBlock);\n\n /**\n * Save changes\n */\n editor.ui.saveInputs();\n\n };\n\n /**\n * @protected\n *\n * Inserts new block to redactor\n * Wrapps block into a DIV with BLOCK_CLASSNAME class\n *\n * @param blockData {object}\n * @param blockData.block {Element} element with block content\n * @param blockData.type {string} block plugin\n * @param needPlaceCaret {bool} pass true to set caret in new block\n *\n */\n content.insertBlock = function ( blockData, needPlaceCaret ) {\n\n var workingBlock = editor.content.currentNode,\n newBlockContent = blockData.block,\n blockType = blockData.type,\n isStretched = blockData.stretched;\n\n var newBlock = composeNewBlock_(newBlockContent, blockType, isStretched);\n\n if (workingBlock) {\n\n editor.core.insertAfter(workingBlock, newBlock);\n\n } else {\n\n /**\n * If redactor is empty, append as first child\n */\n editor.nodes.redactor.appendChild(newBlock);\n\n }\n\n /**\n * Block handler\n */\n editor.ui.addBlockHandlers(newBlock);\n\n /**\n * Set new node as current\n */\n editor.content.workingNodeChanged(newBlock);\n\n /**\n * Save changes\n */\n editor.ui.saveInputs();\n\n\n if ( needPlaceCaret ) {\n\n /**\n * If we don't know input index then we set default value -1\n */\n var currentInputIndex = editor.caret.getCurrentInputIndex() || -1;\n\n\n if (currentInputIndex == -1) {\n\n\n var editableElement = newBlock.querySelector('[contenteditable]'),\n emptyText = document.createTextNode('');\n\n editableElement.appendChild(emptyText);\n editor.caret.set(editableElement, 0, 0);\n\n editor.toolbar.move();\n editor.toolbar.showPlusButton();\n\n\n } else {\n\n if (currentInputIndex === editor.state.inputs.length - 1)\n return;\n\n /** Timeout for browsers execution */\n window.setTimeout(function () {\n\n /** Setting to the new input */\n editor.caret.setToNextBlock(currentInputIndex);\n editor.toolbar.move();\n editor.toolbar.open();\n\n }, 10);\n\n }\n\n }\n\n /**\n * Block is inserted, wait for new click that defined focusing on editors area\n * @type {boolean}\n */\n content.editorAreaHightlighted = false;\n\n };\n\n /**\n * Replaces blocks with saving content\n * @protected\n * @param {Element} noteToReplace\n * @param {Element} newNode\n * @param {Element} blockType\n */\n content.switchBlock = function (blockToReplace, newBlock, tool) {\n\n tool = tool || editor.content.currentNode.dataset.tool;\n var newBlockComposed = composeNewBlock_(newBlock, tool);\n\n /** Replacing */\n editor.content.replaceBlock(blockToReplace, newBlockComposed);\n\n /** Save new Inputs when block is changed */\n editor.ui.saveInputs();\n\n };\n\n /**\n * Iterates between child noted and looking for #text node on deepest level\n * @protected\n *\n * @param {Element} block - node where find\n * @param {int} postiton - starting postion\n * Example: childNodex.length to find from the end\n * or 0 to find from the start\n * @return {Text} block\n * @uses DFS\n */\n content.getDeepestTextNodeFromPosition = function (block, position) {\n\n /**\n * Clear Block from empty and useless spaces with trim.\n * Such nodes we should remove\n */\n var blockChilds = block.childNodes,\n index,\n node,\n text;\n\n for(index = 0; index < blockChilds.length; index++) {\n\n node = blockChilds[index];\n\n if (node.nodeType == editor.core.nodeTypes.TEXT) {\n\n text = node.textContent.trim();\n\n /** Text is empty. We should remove this child from node before we start DFS\n * decrease the quantity of childs.\n */\n if (text === '') {\n\n block.removeChild(node);\n position--;\n\n }\n\n }\n\n }\n\n if (block.childNodes.length === 0) {\n\n return document.createTextNode('');\n\n }\n\n /** Setting default position when we deleted all empty nodes */\n if ( position < 0 )\n position = 1;\n\n var lookingFromStart = false;\n\n /** For looking from START */\n if (position === 0) {\n\n lookingFromStart = true;\n position = 1;\n\n }\n\n while ( position ) {\n\n /** initial verticle of node. */\n if ( lookingFromStart ) {\n\n block = block.childNodes[0];\n\n } else {\n\n block = block.childNodes[position - 1];\n\n }\n\n if ( block.nodeType == editor.core.nodeTypes.TAG ) {\n\n position = block.childNodes.length;\n\n } else if (block.nodeType == editor.core.nodeTypes.TEXT ) {\n\n position = 0;\n\n }\n\n }\n\n return block;\n\n };\n\n /**\n * @private\n * @param {Element} block - current plugins render\n * @param {String} tool - plugins name\n * @param {Boolean} isStretched - make stretched block or not\n *\n * @description adds necessary information to wrap new created block by first-level holder\n */\n var composeNewBlock_ = function (block, tool, isStretched) {\n\n var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),\n blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});\n\n blockContent.appendChild(block);\n newBlock.appendChild(blockContent);\n\n if (isStretched) {\n\n blockContent.classList.add(editor.ui.className.BLOCK_STRETCHED);\n\n }\n\n newBlock.dataset.tool = tool;\n return newBlock;\n\n };\n\n /**\n * Returns Range object of current selection\n * @protected\n */\n content.getRange = function () {\n\n var selection = window.getSelection().getRangeAt(0);\n\n return selection;\n\n };\n\n /**\n * Divides block in two blocks (after and before caret)\n *\n * @protected\n * @param {int} inputIndex - target input index\n *\n * @description splits current input content to the separate blocks\n * When enter is pressed among the words, that text will be splited.\n */\n content.splitBlock = function (inputIndex) {\n\n var selection = window.getSelection(),\n anchorNode = selection.anchorNode,\n anchorNodeText = anchorNode.textContent,\n caretOffset = selection.anchorOffset,\n textBeforeCaret,\n textNodeBeforeCaret,\n textAfterCaret,\n textNodeAfterCaret;\n\n var currentBlock = editor.content.currentNode.querySelector('[contentEditable]');\n\n\n textBeforeCaret = anchorNodeText.substring(0, caretOffset);\n textAfterCaret = anchorNodeText.substring(caretOffset);\n\n textNodeBeforeCaret = document.createTextNode(textBeforeCaret);\n\n if (textAfterCaret) {\n\n textNodeAfterCaret = document.createTextNode(textAfterCaret);\n\n }\n\n var previousChilds = [],\n nextChilds = [],\n reachedCurrent = false;\n\n if (textNodeAfterCaret) {\n\n nextChilds.push(textNodeAfterCaret);\n\n }\n\n for ( var i = 0, child; !!(child = currentBlock.childNodes[i]); i++) {\n\n if ( child != anchorNode ) {\n\n if ( !reachedCurrent ) {\n\n previousChilds.push(child);\n\n } else {\n\n nextChilds.push(child);\n\n }\n\n } else {\n\n reachedCurrent = true;\n\n }\n\n }\n\n /** Clear current input */\n editor.state.inputs[inputIndex].innerHTML = '';\n\n /**\n * Append all childs founded before anchorNode\n */\n var previousChildsLength = previousChilds.length;\n\n for(i = 0; i < previousChildsLength; i++) {\n\n editor.state.inputs[inputIndex].appendChild(previousChilds[i]);\n\n }\n\n editor.state.inputs[inputIndex].appendChild(textNodeBeforeCaret);\n\n /**\n * Append text node which is after caret\n */\n var nextChildsLength = nextChilds.length,\n newNode = document.createElement('div');\n\n for(i = 0; i < nextChildsLength; i++) {\n\n newNode.appendChild(nextChilds[i]);\n\n }\n\n newNode = newNode.innerHTML;\n\n /** This type of block creates when enter is pressed */\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n /**\n * Make new paragraph with text after caret\n */\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render({\n text : newNode\n })\n }, true );\n\n };\n\n /**\n * Merges two blocks — current and target\n * If target index is not exist, then previous will be as target\n *\n * @protected\n * @param {int} currentInputIndex\n * @param {int} targetInputIndex\n *\n * @description gets two inputs indexes and merges into one\n */\n content.mergeBlocks = function (currentInputIndex, targetInputIndex) {\n\n /** If current input index is zero, then prevent method execution */\n if (currentInputIndex === 0) {\n\n return;\n\n }\n\n var targetInput,\n currentInputContent = editor.state.inputs[currentInputIndex].innerHTML;\n\n if (!targetInputIndex) {\n\n targetInput = editor.state.inputs[currentInputIndex - 1];\n\n } else {\n\n targetInput = editor.state.inputs[targetInputIndex];\n\n }\n\n targetInput.innerHTML += currentInputContent;\n\n };\n\n /**\n * Iterates all right siblings and parents, which has right siblings\n * while it does not reached the first-level block\n *\n * @param {Element} node\n * @return {boolean}\n */\n content.isLastNode = function (node) {\n\n // console.log('погнали перебор родителей');\n\n var allChecked = false;\n\n while ( !allChecked ) {\n\n // console.log('Смотрим на %o', node);\n // console.log('Проверим, пустые ли соседи справа');\n\n if ( !allSiblingsEmpty_(node) ) {\n\n // console.log('Есть непустые соседи. Узел не последний. Выходим.');\n return false;\n\n }\n\n node = node.parentNode;\n\n /**\n * Проверяем родителей до тех пор, пока не найдем блок первого уровня\n */\n if ( node.classList.contains(editor.ui.className.BLOCK_CONTENT) ) {\n\n allChecked = true;\n\n }\n\n }\n\n return true;\n\n };\n\n /**\n * Checks if all element right siblings is empty\n * @param node\n */\n var allSiblingsEmpty_ = function (node) {\n\n /**\n * Нужно убедиться, что после пустого соседа ничего нет\n */\n var sibling = node.nextSibling;\n\n while ( sibling ) {\n\n if (sibling.textContent.length) {\n\n return false;\n\n }\n\n sibling = sibling.nextSibling;\n\n }\n\n return true;\n\n };\n\n /**\n * @public\n *\n * @param {string} htmlData - html content as string\n * @param {string} plainData - plain text\n * @return {string} - html content as string\n */\n content.wrapTextWithParagraphs = function (htmlData, plainData) {\n\n if (!htmlData.trim()) {\n\n return wrapPlainTextWithParagraphs(plainData);\n\n }\n\n var wrapper = document.createElement('DIV'),\n newWrapper = document.createElement('DIV'),\n i,\n paragraph,\n firstLevelBlocks = ['DIV', 'P'],\n blockTyped,\n node;\n\n /**\n * Make HTML Element to Wrap Text\n * It allows us to work with input data as HTML content\n */\n wrapper.innerHTML = htmlData;\n paragraph = document.createElement('P');\n\n for (i = 0; i < wrapper.childNodes.length; i++) {\n\n node = wrapper.childNodes[i];\n\n blockTyped = firstLevelBlocks.indexOf(node.tagName) != -1;\n\n /**\n * If node is first-levet\n * we add this node to our new wrapper\n */\n if ( blockTyped ) {\n\n /**\n * If we had splitted inline nodes to paragraph before\n */\n if ( paragraph.childNodes.length ) {\n\n newWrapper.appendChild(paragraph.cloneNode(true));\n\n /** empty paragraph */\n paragraph = null;\n paragraph = document.createElement('P');\n\n }\n\n newWrapper.appendChild(node.cloneNode(true));\n\n } else {\n\n /** Collect all inline nodes to one as paragraph */\n paragraph.appendChild(node.cloneNode(true));\n\n /** if node is last we should append this node to paragraph and paragraph to new wrapper */\n if ( i == wrapper.childNodes.length - 1 ) {\n\n newWrapper.appendChild(paragraph.cloneNode(true));\n\n }\n\n }\n\n }\n\n return newWrapper.innerHTML;\n\n };\n\n /**\n * Splits strings on new line and wraps paragraphs with

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

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

    ') + '

    ';\n\n };\n\n /**\n * Finds closest Contenteditable parent from Element\n * @param {Element} node element looking from\n * @return {Element} node contenteditable\n */\n content.getEditableParent = function (node) {\n\n while (node && node.contentEditable != 'true') {\n\n node = node.parentNode;\n\n }\n\n return node;\n\n };\n\n /**\n * Clear editors content\n *\n * @param {Boolean} all — if true, delete all article data (content, id, etc.)\n */\n content.clear = function (all) {\n\n editor.nodes.redactor.innerHTML = '';\n editor.content.sync();\n editor.ui.saveInputs();\n if (all) {\n\n editor.state.blocks = {};\n\n } else if (editor.state.blocks) {\n\n editor.state.blocks.items = [];\n\n }\n\n editor.content.currentNode = null;\n\n };\n\n /**\n *\n * Load new data to editor\n * If editor is not empty, just append articleData.items\n *\n * @param articleData.items\n */\n content.load = function (articleData) {\n\n var currentContent = Object.assign({}, editor.state.blocks);\n\n editor.content.clear();\n\n if (!Object.keys(currentContent).length) {\n\n editor.state.blocks = articleData;\n\n } else if (!currentContent.items) {\n\n currentContent.items = articleData.items;\n editor.state.blocks = currentContent;\n\n } else {\n\n currentContent.items = currentContent.items.concat(articleData.items);\n editor.state.blocks = currentContent;\n\n }\n\n editor.renderer.makeBlocksFromData();\n\n };\n\n return content;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/content.js","/**\n * Codex Editor toolbar module\n *\n * Contains:\n * - Inline toolbox\n * - Toolbox within plus button\n * - Settings section\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (toolbar) {\n\n let editor = codex.editor;\n\n toolbar.settings = require('./settings');\n toolbar.inline = require('./inline');\n toolbar.toolbox = require('./toolbox');\n\n /**\n * Margin between focused node and toolbar\n */\n toolbar.defaultToolbarHeight = 49;\n\n toolbar.defaultOffset = 34;\n\n toolbar.opened = false;\n\n toolbar.current = null;\n\n /**\n * @protected\n */\n toolbar.open = function () {\n\n if (editor.hideToolbar) {\n\n return;\n\n }\n\n let toolType = editor.content.currentNode.dataset.tool;\n\n if (!editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {\n\n editor.nodes.showSettingsButton.classList.add('hide');\n\n } else {\n\n editor.nodes.showSettingsButton.classList.remove('hide');\n\n }\n\n editor.nodes.toolbar.classList.add('opened');\n this.opened = true;\n\n };\n\n /**\n * @protected\n */\n toolbar.close = function () {\n\n editor.nodes.toolbar.classList.remove('opened');\n\n toolbar.opened = false;\n toolbar.current = null;\n\n for (var button in editor.nodes.toolbarButtons) {\n\n editor.nodes.toolbarButtons[button].classList.remove('selected');\n\n }\n\n /** Close toolbox when toolbar is not displayed */\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.close();\n\n };\n\n toolbar.toggle = function () {\n\n if ( !this.opened ) {\n\n this.open();\n\n } else {\n\n this.close();\n\n }\n\n };\n\n toolbar.hidePlusButton = function () {\n\n editor.nodes.plusButton.classList.add('hide');\n\n };\n\n toolbar.showPlusButton = function () {\n\n editor.nodes.plusButton.classList.remove('hide');\n\n };\n\n /**\n * Moving toolbar to the specified node\n */\n toolbar.move = function () {\n\n /** Close Toolbox when we move toolbar */\n editor.toolbar.toolbox.close();\n\n if (!editor.content.currentNode) {\n\n return;\n\n }\n\n var newYCoordinate = editor.content.currentNode.offsetTop - (editor.toolbar.defaultToolbarHeight / 2) + editor.toolbar.defaultOffset;\n\n editor.nodes.toolbar.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;\n\n /** Close trash actions */\n editor.toolbar.settings.hideRemoveActions();\n\n };\n\n return toolbar;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/toolbar.js","/**\n * Toolbar settings\n *\n * @version 1.0.5\n */\n\nmodule.exports = (function (settings) {\n\n let editor = codex.editor;\n\n settings.opened = false;\n\n settings.setting = null;\n settings.actions = null;\n\n /**\n * Append and open settings\n */\n settings.open = function (toolType) {\n\n /**\n * Append settings content\n * It's stored in tool.settings\n */\n if ( !editor.tools[toolType] || !editor.tools[toolType].makeSettings ) {\n\n return;\n\n }\n\n /**\n * Draw settings block\n */\n var settingsBlock = editor.tools[toolType].makeSettings();\n\n editor.nodes.pluginSettings.appendChild(settingsBlock);\n\n\n /** Open settings block */\n editor.nodes.blockSettings.classList.add('opened');\n this.opened = true;\n\n };\n\n /**\n * Close and clear settings\n */\n settings.close = function () {\n\n editor.nodes.blockSettings.classList.remove('opened');\n editor.nodes.pluginSettings.innerHTML = '';\n\n this.opened = false;\n\n };\n\n /**\n * @param {string} toolType - plugin type\n */\n settings.toggle = function ( toolType ) {\n\n if ( !this.opened ) {\n\n this.open(toolType);\n\n } else {\n\n this.close();\n\n }\n\n };\n\n /**\n * Here we will draw buttons and add listeners to components\n */\n settings.makeRemoveBlockButton = function () {\n\n var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}),\n settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML : '' }),\n actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),\n confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent : 'Удалить блок' }),\n cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent : 'Отмена' });\n\n editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);\n\n editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);\n\n editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);\n\n actionWrapper.appendChild(confirmAction);\n actionWrapper.appendChild(cancelAction);\n\n removeBlockWrapper.appendChild(settingButton);\n removeBlockWrapper.appendChild(actionWrapper);\n\n /** Save setting */\n editor.toolbar.settings.setting = settingButton;\n editor.toolbar.settings.actions = actionWrapper;\n\n return removeBlockWrapper;\n\n };\n\n settings.removeButtonClicked = function () {\n\n var action = editor.toolbar.settings.actions;\n\n if (action.classList.contains('opened')) {\n\n editor.toolbar.settings.hideRemoveActions();\n\n } else {\n\n editor.toolbar.settings.showRemoveActions();\n\n }\n\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.close();\n\n };\n\n settings.cancelRemovingRequest = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n settings.confirmRemovingRequest = function () {\n\n var currentBlock = editor.content.currentNode,\n firstLevelBlocksCount;\n\n currentBlock.remove();\n\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\n /**\n * If all blocks are removed\n */\n if (firstLevelBlocksCount === 0) {\n\n /** update currentNode variable */\n editor.content.currentNode = null;\n\n /** Inserting new empty initial block */\n editor.ui.addInitialBlock();\n\n }\n\n editor.ui.saveInputs();\n\n editor.toolbar.close();\n\n };\n\n settings.showRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.add('opened');\n\n };\n\n settings.hideRemoveActions = function () {\n\n editor.toolbar.settings.actions.classList.remove('opened');\n\n };\n\n return settings;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/settings.js","/**\n * Inline toolbar\n *\n * Contains from tools:\n * Bold, Italic, Underline and Anchor\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (inline) {\n\n let editor = codex.editor;\n\n inline.buttonsOpened = null;\n inline.actionsOpened = null;\n inline.wrappersOffset = null;\n\n /**\n * saving selection that need for execCommand for styling\n *\n */\n inline.storedSelection = null;\n\n /**\n * @protected\n *\n * Open inline toobar\n */\n inline.show = function () {\n\n var currentNode = editor.content.currentNode,\n tool = currentNode.dataset.tool,\n plugin;\n\n /**\n * tool allowed to open inline toolbar\n */\n plugin = editor.tools[tool];\n\n if (!plugin.showInlineToolbar)\n return;\n\n var selectedText = inline.getSelectionText(),\n toolbar = editor.nodes.inlineToolbar.wrapper;\n\n if (selectedText.length > 0) {\n\n /** Move toolbar and open */\n editor.toolbar.inline.move();\n\n /** Open inline toolbar */\n toolbar.classList.add('opened');\n\n /** show buttons of inline toolbar */\n editor.toolbar.inline.showButtons();\n\n }\n\n };\n\n /**\n * @protected\n *\n * Closes inline toolbar\n */\n inline.close = function () {\n\n var toolbar = editor.nodes.inlineToolbar.wrapper;\n\n toolbar.classList.remove('opened');\n\n };\n\n /**\n * @private\n *\n * Moving toolbar\n */\n inline.move = function () {\n\n if (!this.wrappersOffset) {\n\n this.wrappersOffset = this.getWrappersOffset();\n\n }\n\n var coords = this.getSelectionCoords(),\n defaultOffset = 0,\n toolbar = editor.nodes.inlineToolbar.wrapper,\n newCoordinateX,\n newCoordinateY;\n\n if (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 toolbox.openedOnBlock = null;\n\n /** Shows toolbox */\n toolbox.open = function () {\n\n /** Close setting if toolbox is opened */\n if (editor.toolbar.settings.opened) {\n\n editor.toolbar.settings.close();\n\n }\n\n /** Add 'toolbar-opened' class for current block **/\n toolbox.openedOnBlock = editor.content.currentNode;\n toolbox.openedOnBlock.classList.add('toolbar-opened');\n\n /** display toolbox */\n editor.nodes.toolbox.classList.add('opened');\n\n /** Animate plus button */\n editor.nodes.plusButton.classList.add('clicked');\n\n /** toolbox state */\n editor.toolbar.toolbox.opened = true;\n\n };\n\n /** Closes toolbox */\n toolbox.close = function () {\n\n /** Remove 'toolbar-opened' class from current block **/\n if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened');\n toolbox.openedOnBlock = null;\n\n /** Makes toolbox disappear */\n editor.nodes.toolbox.classList.remove('opened');\n\n /** Rotate plus button */\n editor.nodes.plusButton.classList.remove('clicked');\n\n /** toolbox state */\n editor.toolbar.toolbox.opened = false;\n\n editor.toolbar.current = null;\n\n };\n\n toolbox.leaf = function () {\n\n let currentTool = editor.toolbar.current,\n tools = Object.keys(editor.tools),\n barButtons = editor.nodes.toolbarButtons,\n nextToolIndex = 0,\n toolToSelect,\n visibleTool,\n tool;\n\n if ( !currentTool ) {\n\n /** Get first tool from object*/\n for(tool in editor.tools) {\n\n if (editor.tools[tool].displayInToolbox) {\n\n break;\n\n }\n\n nextToolIndex ++;\n\n }\n\n } else {\n\n nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;\n visibleTool = tools[nextToolIndex];\n\n while (!editor.tools[visibleTool].displayInToolbox) {\n\n nextToolIndex = (nextToolIndex + 1) % tools.length;\n visibleTool = tools[nextToolIndex];\n\n }\n\n }\n\n toolToSelect = tools[nextToolIndex];\n\n for ( var button in barButtons ) {\n\n barButtons[button].classList.remove('selected');\n\n }\n\n barButtons[toolToSelect].classList.add('selected');\n editor.toolbar.current = toolToSelect;\n\n };\n\n /**\n * Transforming selected node type into selected toolbar element type\n * @param {event} event\n */\n toolbox.toolClicked = function (event) {\n\n /**\n * UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty\n */\n var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],\n tool = editor.tools[editor.toolbar.current],\n workingNode = editor.content.currentNode,\n currentInputIndex = editor.caret.inputIndex,\n newBlockContent,\n appendCallback,\n blockData;\n\n /** Make block from plugin */\n newBlockContent = tool.render();\n\n /** information about block */\n blockData = {\n block : newBlockContent,\n type : tool.type,\n stretched : false\n };\n\n if (\n workingNode &&\n UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 &&\n workingNode.textContent.trim() === ''\n ) {\n\n /** Replace current block */\n editor.content.switchBlock(workingNode, newBlockContent, tool.type);\n\n } else {\n\n /** Insert new Block from plugin */\n editor.content.insertBlock(blockData);\n\n /** increase input index */\n currentInputIndex++;\n\n }\n\n /** Fire tool append callback */\n appendCallback = tool.appendCallback;\n\n if (appendCallback && typeof appendCallback == 'function') {\n\n appendCallback.call(event);\n\n }\n\n window.setTimeout(function () {\n\n /** Set caret to current block */\n editor.caret.setToBlock(currentInputIndex);\n\n }, 10);\n\n\n /**\n * Changing current Node\n */\n editor.content.workingNodeChanged();\n\n /**\n * Move toolbar when node is changed\n */\n editor.toolbar.move();\n\n };\n\n return toolbox;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/toolbar/toolbox.js","/**\n * @module Codex Editor Callbacks module\n * @description Module works with editor added Elements\n *\n * @author Codex Team\n * @version 1.4.0\n */\n\nmodule.exports = (function (callbacks) {\n\n let editor = codex.editor;\n\n /**\n * used by UI module\n * @description Routes all keydowns on document\n * @param {Object} event\n */\n callbacks.globalKeydown = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.ENTER : enterKeyPressed_(event); break;\n }\n\n };\n\n /**\n * used by UI module\n * @description Routes all keydowns on redactors area\n * @param {Object} event\n */\n callbacks.redactorKeyDown = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.TAB : tabKeyPressedOnRedactorsZone_(event); break;\n case editor.core.keys.ENTER : enterKeyPressedOnRedactorsZone_(event); break;\n case editor.core.keys.ESC : escapeKeyPressedOnRedactorsZone_(event); break;\n default : defaultKeyPressedOnRedactorsZone_(event); break;\n }\n\n };\n\n /**\n * used by UI module\n * @description Routes all keyup events\n * @param {Object} event\n */\n callbacks.globalKeyup = function (event) {\n\n switch (event.keyCode) {\n case editor.core.keys.UP :\n case editor.core.keys.LEFT :\n case editor.core.keys.RIGHT :\n case editor.core.keys.DOWN : arrowKeyPressed_(event); break;\n }\n\n };\n\n /**\n * @param {Object} event\n * @private\n *\n * Handles behaviour when tab pressed\n * @description if Content is empty show toolbox (if it is closed) or leaf tools\n * uses Toolbars toolbox module to handle the situation\n */\n var tabKeyPressedOnRedactorsZone_ = function (event) {\n\n /**\n * Wait for solution. Would like to know the behaviour\n * @todo Add spaces\n */\n event.preventDefault();\n\n\n if (!editor.core.isBlockEmpty(editor.content.currentNode)) {\n\n return;\n\n }\n\n if ( !editor.toolbar.opened ) {\n\n editor.toolbar.open();\n\n }\n\n if (editor.toolbar.opened && !editor.toolbar.toolbox.opened) {\n\n editor.toolbar.toolbox.open();\n\n } else {\n\n editor.toolbar.toolbox.leaf();\n\n }\n\n };\n\n /**\n * Handles global EnterKey Press\n * @see enterPressedOnBlock_\n * @param {Object} event\n */\n var enterKeyPressed_ = function () {\n\n if (editor.content.editorAreaHightlighted) {\n\n /**\n * it means that we lose input index, saved index before is not correct\n * therefore we need to set caret when we insert new block\n */\n editor.caret.inputIndex = -1;\n\n enterPressedOnBlock_();\n\n }\n\n };\n\n /**\n * Callback for enter key pressing in first-level block area\n *\n * @param {Event} event\n * @private\n *\n * @description Inserts new block with initial type from settings\n */\n var enterPressedOnBlock_ = function () {\n\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render()\n }, true );\n\n editor.toolbar.move();\n editor.toolbar.open();\n\n };\n\n\n /**\n * ENTER key handler\n *\n * @param {Object} event\n * @private\n *\n * @description Makes new block with initial type from settings\n */\n var enterKeyPressedOnRedactorsZone_ = function (event) {\n\n if (event.target.contentEditable == 'true') {\n\n /** Update input index */\n editor.caret.saveCurrentInputIndex();\n\n }\n\n var currentInputIndex = editor.caret.getCurrentInputIndex() || 0,\n workingNode = editor.content.currentNode,\n tool = workingNode.dataset.tool,\n isEnterPressedOnToolbar = editor.toolbar.opened &&\n editor.toolbar.current &&\n event.target == editor.state.inputs[currentInputIndex];\n\n /** The list of tools which needs the default browser behaviour */\n var enableLineBreaks = editor.tools[tool].enableLineBreaks;\n\n /** This type of block creates when enter is pressed */\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n /**\n * When toolbar is opened, select tool instead of making new paragraph\n */\n if ( isEnterPressedOnToolbar ) {\n\n event.preventDefault();\n\n editor.toolbar.toolbox.toolClicked(event);\n\n editor.toolbar.close();\n\n /**\n * Stop other listeners callback executions\n */\n event.stopPropagation();\n event.stopImmediatePropagation();\n\n return;\n\n }\n\n /**\n * Allow paragraph lineBreaks with shift enter\n * Or if shiftkey pressed and enter and enabledLineBreaks, the let new block creation\n */\n if ( event.shiftKey || enableLineBreaks ) {\n\n event.stopPropagation();\n event.stopImmediatePropagation();\n return;\n\n }\n\n var currentSelection = window.getSelection(),\n currentSelectedNode = currentSelection.anchorNode,\n caretAtTheEndOfText = editor.caret.position.atTheEnd(),\n isTextNodeHasParentBetweenContenteditable = false;\n\n /**\n * Allow making new

    in same block by SHIFT+ENTER and forbids to prevent default browser behaviour\n */\n if ( event.shiftKey && !enableLineBreaks ) {\n\n editor.callback.enterPressedOnBlock(editor.content.currentBlock, event);\n event.preventDefault();\n return;\n\n }\n\n /**\n * Workaround situation when caret at the Text node that has some wrapper Elements\n * Split block cant handle this.\n * We need to save default behavior\n */\n isTextNodeHasParentBetweenContenteditable = currentSelectedNode && currentSelectedNode.parentNode.contentEditable != 'true';\n\n /**\n * Split blocks when input has several nodes and caret placed in textNode\n */\n if (\n currentSelectedNode.nodeType == editor.core.nodeTypes.TEXT &&\n !isTextNodeHasParentBetweenContenteditable &&\n !caretAtTheEndOfText\n ) {\n\n event.preventDefault();\n\n editor.core.log('Splitting Text node...');\n\n editor.content.splitBlock(currentInputIndex);\n\n /** Show plus button when next input after split is empty*/\n if (!editor.state.inputs[currentInputIndex + 1].textContent.trim()) {\n\n editor.toolbar.showPlusButton();\n\n }\n\n } else {\n\n var islastNode = editor.content.isLastNode(currentSelectedNode);\n\n if ( islastNode && caretAtTheEndOfText ) {\n\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n\n editor.core.log('ENTER clicked in last textNode. Create new BLOCK');\n\n editor.content.insertBlock({\n type: NEW_BLOCK_TYPE,\n block: editor.tools[NEW_BLOCK_TYPE].render()\n }, true);\n\n editor.toolbar.move();\n editor.toolbar.open();\n\n /** Show plus button with empty block */\n editor.toolbar.showPlusButton();\n\n }\n\n }\n\n /** get all inputs after new appending block */\n editor.ui.saveInputs();\n\n };\n\n /**\n * Escape behaviour\n * @param event\n * @private\n *\n * @description Closes toolbox and toolbar. Prevents default behaviour\n */\n var escapeKeyPressedOnRedactorsZone_ = function (event) {\n\n /** Close all toolbar */\n editor.toolbar.close();\n\n /** Close toolbox */\n editor.toolbar.toolbox.close();\n\n event.preventDefault();\n\n };\n\n /**\n * @param {Event} event\n * @private\n *\n * closes and moves toolbar\n */\n var arrowKeyPressed_ = function (event) {\n\n editor.content.workingNodeChanged();\n\n /* Closing toolbar */\n editor.toolbar.close();\n editor.toolbar.move();\n\n };\n\n /**\n * @private\n * @param {Event} event\n *\n * @description Closes all opened bars from toolbar.\n * If block is mark, clears highlightning\n */\n var defaultKeyPressedOnRedactorsZone_ = function () {\n\n editor.toolbar.close();\n\n if (!editor.toolbar.inline.actionsOpened) {\n\n editor.toolbar.inline.close();\n editor.content.clearMark();\n\n }\n\n };\n\n /**\n * Handler when clicked on redactors area\n *\n * @protected\n * @param event\n *\n * @description Detects clicked area. If it is first-level block area, marks as detected and\n * on next enter press will be inserted new block\n * Otherwise, save carets position (input index) and put caret to the editable zone.\n *\n * @see detectWhenClickedOnFirstLevelBlockArea_\n *\n */\n callbacks.redactorClicked = function (event) {\n\n detectWhenClickedOnFirstLevelBlockArea_();\n\n editor.content.workingNodeChanged(event.target);\n editor.ui.saveInputs();\n\n var selectedText = editor.toolbar.inline.getSelectionText(),\n firstLevelBlock;\n\n /** If selection range took off, then we hide inline toolbar */\n if (selectedText.length === 0) {\n\n editor.toolbar.inline.close();\n\n }\n\n /** Update current input index in memory when caret focused into existed input */\n if (event.target.contentEditable == 'true') {\n\n editor.caret.saveCurrentInputIndex();\n\n }\n\n if (editor.content.currentNode === null) {\n\n /**\n * If inputs in redactor does not exits, then we put input index 0 not -1\n */\n var indexOfLastInput = editor.state.inputs.length > 0 ? editor.state.inputs.length - 1 : 0;\n\n /** If we have any inputs */\n if (editor.state.inputs.length) {\n\n /** getting firstlevel parent of input */\n firstLevelBlock = editor.content.getFirstLevelBlock(editor.state.inputs[indexOfLastInput]);\n\n }\n\n /** If input is empty, then we set caret to the last input */\n if (editor.state.inputs.length && editor.state.inputs[indexOfLastInput].textContent === '' && firstLevelBlock.dataset.tool == editor.settings.initialBlockPlugin) {\n\n editor.caret.setToBlock(indexOfLastInput);\n\n } else {\n\n /** Create new input when caret clicked in redactors area */\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin;\n\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render()\n });\n\n /** If there is no inputs except inserted */\n if (editor.state.inputs.length === 1) {\n\n editor.caret.setToBlock(indexOfLastInput);\n\n } else {\n\n /** Set caret to this appended input */\n editor.caret.setToNextBlock(indexOfLastInput);\n\n }\n\n }\n\n } else {\n\n /** Close all panels */\n editor.toolbar.settings.close();\n editor.toolbar.toolbox.close();\n\n }\n\n /**\n * Move toolbar and open\n */\n editor.toolbar.move();\n editor.toolbar.open();\n\n var inputIsEmpty = !editor.content.currentNode.textContent.trim(),\n currentNodeType = editor.content.currentNode.dataset.tool,\n isInitialType = currentNodeType == editor.settings.initialBlockPlugin;\n\n\n /** Hide plus buttons */\n editor.toolbar.hidePlusButton();\n\n if (!inputIsEmpty) {\n\n /** Mark current block */\n editor.content.markBlock();\n\n }\n\n if ( isInitialType && inputIsEmpty ) {\n\n /** Show plus button */\n editor.toolbar.showPlusButton();\n\n }\n\n\n };\n\n /**\n * This method allows to define, is caret in contenteditable element or not.\n *\n * @private\n *\n * @description Otherwise, if we get TEXT node from range container, that will means we have input index.\n * In this case we use default browsers behaviour (if plugin allows that) or overwritten action.\n * Therefore, to be sure that we've clicked first-level block area, we should have currentNode, which always\n * specifies to the first-level block. Other cases we just ignore.\n */\n var detectWhenClickedOnFirstLevelBlockArea_ = function () {\n\n var selection = window.getSelection(),\n anchorNode = selection.anchorNode,\n flag = false;\n\n if (selection.rangeCount === 0) {\n\n editor.content.editorAreaHightlighted = true;\n\n } else {\n\n if (!editor.core.isDomNode(anchorNode)) {\n\n anchorNode = anchorNode.parentNode;\n\n }\n\n /** Already founded, without loop */\n if (anchorNode.contentEditable == 'true') {\n\n flag = true;\n\n }\n\n while (anchorNode.contentEditable != 'true') {\n\n anchorNode = anchorNode.parentNode;\n\n if (anchorNode.contentEditable == 'true') {\n\n flag = true;\n\n }\n\n if (anchorNode == document.body) {\n\n break;\n\n }\n\n }\n\n /** If editable element founded, flag is \"TRUE\", Therefore we return \"FALSE\" */\n editor.content.editorAreaHightlighted = !flag;\n\n }\n\n };\n\n /**\n * Toolbar button click handler\n *\n * @param {Object} event - cursor to the button\n * @protected\n *\n * @description gets current tool and calls render method\n */\n callbacks.toolbarButtonClicked = function (event) {\n\n var button = this;\n\n editor.toolbar.current = button.dataset.type;\n\n editor.toolbar.toolbox.toolClicked(event);\n editor.toolbar.close();\n\n };\n\n /**\n * Show or Hide toolbox when plus button is clicked\n */\n callbacks.plusButtonClicked = function () {\n\n if (!editor.nodes.toolbox.classList.contains('opened')) {\n\n editor.toolbar.toolbox.open();\n\n } else {\n\n editor.toolbar.toolbox.close();\n\n }\n\n };\n\n /**\n * Block handlers for KeyDown events\n *\n * @protected\n * @param {Object} event\n *\n * Handles keydowns on block\n * @see blockRightOrDownArrowPressed_\n * @see backspacePressed_\n * @see blockLeftOrUpArrowPressed_\n */\n callbacks.blockKeydown = function (event) {\n\n let block = event.target; // event.target is input\n\n switch (event.keyCode) {\n\n case editor.core.keys.DOWN:\n case editor.core.keys.RIGHT:\n blockRightOrDownArrowPressed_(event);\n break;\n\n case editor.core.keys.BACKSPACE:\n backspacePressed_(block, event);\n break;\n\n case editor.core.keys.UP:\n case editor.core.keys.LEFT:\n blockLeftOrUpArrowPressed_(event);\n break;\n\n }\n\n };\n\n /**\n * RIGHT or DOWN keydowns on block\n *\n * @param {Object} event\n * @private\n *\n * @description watches the selection and gets closest editable element.\n * Uses method getDeepestTextNodeFromPosition to get the last node of next block\n * Sets caret if it is contenteditable\n */\n var blockRightOrDownArrowPressed_ = function (event) {\n\n var selection = window.getSelection(),\n inputs = editor.state.inputs,\n focusedNode = selection.anchorNode,\n focusedNodeHolder;\n\n /** Check for caret existance */\n if (!focusedNode) {\n\n return false;\n\n }\n\n /** Looking for closest (parent) contentEditable element of focused node */\n while (focusedNode.contentEditable != 'true') {\n\n focusedNodeHolder = focusedNode.parentNode;\n focusedNode = focusedNodeHolder;\n\n }\n\n /** Input index in DOM level */\n var editableElementIndex = 0;\n\n while (focusedNode != inputs[editableElementIndex]) {\n\n editableElementIndex ++;\n\n }\n\n /**\n * Founded contentEditable element doesn't have childs\n * Or maybe New created block\n */\n if (!focusedNode.textContent) {\n\n editor.caret.setToNextBlock(editableElementIndex);\n return;\n\n }\n\n /**\n * Do nothing when caret doesn not reaches the end of last child\n */\n var caretInLastChild = false,\n caretAtTheEndOfText = false;\n\n var lastChild,\n deepestTextnode;\n\n lastChild = focusedNode.childNodes[focusedNode.childNodes.length - 1 ];\n\n if (editor.core.isDomNode(lastChild)) {\n\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(lastChild, lastChild.childNodes.length);\n\n } else {\n\n deepestTextnode = lastChild;\n\n }\n\n caretInLastChild = selection.anchorNode == deepestTextnode;\n caretAtTheEndOfText = deepestTextnode.length == selection.anchorOffset;\n\n if ( !caretInLastChild || !caretAtTheEndOfText ) {\n\n editor.core.log('arrow [down|right] : caret does not reached the end');\n return false;\n\n }\n\n editor.caret.setToNextBlock(editableElementIndex);\n\n };\n\n /**\n * LEFT or UP keydowns on block\n *\n * @param {Object} event\n * @private\n *\n * watches the selection and gets closest editable element.\n * Uses method getDeepestTextNodeFromPosition to get the last node of previous block\n * Sets caret if it is contenteditable\n *\n */\n var blockLeftOrUpArrowPressed_ = function (event) {\n\n var selection = window.getSelection(),\n inputs = editor.state.inputs,\n focusedNode = selection.anchorNode,\n focusedNodeHolder;\n\n /** Check for caret existance */\n if (!focusedNode) {\n\n return false;\n\n }\n\n /**\n * LEFT or UP not at the beginning\n */\n if ( selection.anchorOffset !== 0) {\n\n return false;\n\n }\n\n /** Looking for parent contentEditable block */\n while (focusedNode.contentEditable != 'true') {\n\n focusedNodeHolder = focusedNode.parentNode;\n focusedNode = focusedNodeHolder;\n\n }\n\n /** Input index in DOM level */\n var editableElementIndex = 0;\n\n while (focusedNode != inputs[editableElementIndex]) {\n\n editableElementIndex ++;\n\n }\n\n /**\n * Do nothing if caret is not at the beginning of first child\n */\n var caretInFirstChild = false,\n caretAtTheBeginning = false;\n\n var firstChild,\n deepestTextnode;\n\n /**\n * Founded contentEditable element doesn't have childs\n * Or maybe New created block\n */\n if (!focusedNode.textContent) {\n\n editor.caret.setToPreviousBlock(editableElementIndex);\n return;\n\n }\n\n firstChild = focusedNode.childNodes[0];\n\n if (editor.core.isDomNode(firstChild)) {\n\n deepestTextnode = editor.content.getDeepestTextNodeFromPosition(firstChild, 0);\n\n } else {\n\n deepestTextnode = firstChild;\n\n }\n\n caretInFirstChild = selection.anchorNode == deepestTextnode;\n caretAtTheBeginning = selection.anchorOffset === 0;\n\n if ( caretInFirstChild && caretAtTheBeginning ) {\n\n editor.caret.setToPreviousBlock(editableElementIndex);\n\n }\n\n };\n\n /**\n * Handles backspace keydown\n *\n * @param {Element} block\n * @param {Object} event\n * @private\n *\n * @description if block is empty, delete the block and set caret to the previous block\n * If block is not empty, try to merge two blocks - current and previous\n * But it we try'n to remove first block, then we should set caret to the next block, not previous.\n * If we removed the last block, create new one\n */\n var backspacePressed_ = function (block, event) {\n\n var currentInputIndex = editor.caret.getCurrentInputIndex(),\n range,\n selectionLength,\n firstLevelBlocksCount;\n\n if (editor.core.isNativeInput(event.target)) {\n\n /** If input value is empty - remove block */\n if (event.target.value.trim() == '') {\n\n block.remove();\n\n } else {\n\n return;\n\n }\n\n }\n\n if (block.textContent.trim()) {\n\n range = editor.content.getRange();\n selectionLength = range.endOffset - range.startOffset;\n\n if (editor.caret.position.atStart() && !selectionLength && editor.state.inputs[currentInputIndex - 1]) {\n\n editor.content.mergeBlocks(currentInputIndex);\n\n } else {\n\n return;\n\n }\n\n }\n\n if (!selectionLength) {\n\n block.remove();\n\n }\n\n\n firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;\n\n /**\n * If all blocks are removed\n */\n if (firstLevelBlocksCount === 0) {\n\n /** update currentNode variable */\n editor.content.currentNode = null;\n\n /** Inserting new empty initial block */\n editor.ui.addInitialBlock();\n\n /** Updating inputs state after deleting last block */\n editor.ui.saveInputs();\n\n /** Set to current appended block */\n window.setTimeout(function () {\n\n editor.caret.setToPreviousBlock(1);\n\n }, 10);\n\n } else {\n\n if (editor.caret.inputIndex !== 0) {\n\n /** Target block is not first */\n editor.caret.setToPreviousBlock(editor.caret.inputIndex);\n\n } else {\n\n /** If we try to delete first block */\n editor.caret.setToNextBlock(editor.caret.inputIndex);\n\n }\n\n }\n\n editor.toolbar.move();\n\n if (!editor.toolbar.opened) {\n\n editor.toolbar.open();\n\n }\n\n /** Updating inputs state */\n editor.ui.saveInputs();\n\n /** Prevent default browser behaviour */\n event.preventDefault();\n\n };\n\n /**\n * used by UI module\n * Clicks on block settings button\n *\n * @param {Object} event\n * @protected\n * @description Opens toolbar settings\n */\n callbacks.showSettingsButtonClicked = function (event) {\n\n /**\n * Get type of current block\n * It uses to append settings from tool.settings property.\n * ...\n * Type is stored in data-type attribute on block\n */\n var currentToolType = editor.content.currentNode.dataset.tool;\n\n editor.toolbar.settings.toggle(currentToolType);\n\n /** Close toolbox when settings button is active */\n editor.toolbar.toolbox.close();\n editor.toolbar.settings.hideRemoveActions();\n\n };\n\n return callbacks;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/callbacks.js","/**\n * Codex Editor Draw module\n *\n * @author Codex Team\n * @version 1.0.\n */\n\nmodule.exports = (function (draw) {\n\n /**\n * Base editor wrapper\n */\n draw.wrapper = function () {\n\n var wrapper = document.createElement('div');\n\n wrapper.className += 'codex-editor';\n\n return wrapper;\n\n };\n\n /**\n * Content-editable holder\n */\n draw.redactor = function () {\n\n var redactor = document.createElement('div');\n\n redactor.className += 'ce-redactor';\n\n return redactor;\n\n };\n\n draw.ceBlock = function () {\n\n var block = document.createElement('DIV');\n\n block.className += 'ce_block';\n\n return block;\n\n };\n\n /**\n * Empty toolbar with toggler\n */\n draw.toolbar = function () {\n\n var bar = document.createElement('div');\n\n bar.className += 'ce-toolbar';\n\n return bar;\n\n };\n\n draw.toolbarContent = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.classList.add('ce-toolbar__content');\n\n return wrapper;\n\n };\n\n /**\n * Inline toolbar\n */\n draw.inlineToolbar = function () {\n\n var bar = document.createElement('DIV');\n\n bar.className += 'ce-toolbar-inline';\n\n return bar;\n\n };\n\n /**\n * Wrapper for inline toobar buttons\n */\n draw.inlineToolbarButtons = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.className += 'ce-toolbar-inline__buttons';\n\n return wrapper;\n\n };\n\n /**\n * For some actions\n */\n draw.inlineToolbarActions = function () {\n\n var wrapper = document.createElement('DIV');\n\n wrapper.className += 'ce-toolbar-inline__actions';\n\n return wrapper;\n\n };\n\n draw.inputForLink = function () {\n\n var input = document.createElement('INPUT');\n\n input.type = 'input';\n input.className += 'inputForLink';\n input.placeholder = 'Вставьте ссылку ...';\n input.setAttribute('form', 'defaultForm');\n\n input.setAttribute('autofocus', 'autofocus');\n\n return input;\n\n };\n\n /**\n * @todo Desc\n */\n draw.blockButtons = function () {\n\n var block = document.createElement('div');\n\n block.className += 'ce-toolbar__actions';\n\n return block;\n\n };\n\n /**\n * Block settings panel\n */\n draw.blockSettings = function () {\n\n var settings = document.createElement('div');\n\n settings.className += 'ce-settings';\n\n return settings;\n\n };\n\n draw.defaultSettings = function () {\n\n var div = document.createElement('div');\n\n div.classList.add('ce-settings_default');\n\n return div;\n\n };\n\n draw.pluginsSettings = function () {\n\n var div = document.createElement('div');\n\n div.classList.add('ce-settings_plugin');\n\n return div;\n\n };\n\n draw.plusButton = function () {\n\n var button = document.createElement('span');\n\n button.className = 'ce-toolbar__plus';\n // button.innerHTML = '';\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\n /**\n * Inserts node at the caret location\n * @param {HTMLElement|DocumentFragment} node\n */\n caret.insertNode = function (node) {\n\n var selection, range,\n lastNode = node;\n\n if (node.nodeType == editor.core.nodeTypes.DOCUMENT_FRAGMENT) {\n\n lastNode = node.lastChild;\n\n }\n\n selection = window.getSelection();\n\n range = selection.getRangeAt(0);\n range.deleteContents();\n\n range.insertNode(node);\n\n range.setStartAfter(lastNode);\n range.collapse(true);\n\n selection.removeAllRanges();\n selection.addRange(range);\n\n\n };\n\n return caret;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/caret.js","/**\n * Codex Editor Notification Module\n *\n * @author Codex Team\n * @version 1.0\n */\n\nmodule.exports = (function (notifications) {\n\n let editor = codex.editor;\n\n var queue = [];\n\n var addToQueue = function (settings) {\n\n queue.push(settings);\n\n var index = 0;\n\n while ( index < queue.length && queue.length > 5) {\n\n if (queue[index].type == 'confirm' || queue[index].type == 'prompt') {\n\n index++;\n continue;\n\n }\n\n queue[index].close();\n queue.splice(index, 1);\n\n }\n\n };\n\n notifications.createHolder = function () {\n\n var holder = editor.draw.node('DIV', 'cdx-notifications-block');\n\n editor.nodes.notifications = document.body.appendChild(holder);\n\n return holder;\n\n };\n\n\n /**\n * Error notificator. Shows block with message\n * @protected\n */\n notifications.errorThrown = function (errorMsg, event) {\n\n editor.notifications.notification({message: 'This action is not available currently', type: event.type});\n\n };\n\n /**\n *\n * Appends notification\n *\n * settings = {\n * type - notification type (reserved types: alert, confirm, prompt). Just add class 'cdx-notification-'+type\n * message - notification message\n * okMsg - confirm button text (default - 'Ok')\n * cancelBtn - cancel button text (default - 'Cancel'). Only for confirm and prompt types\n * confirm - function-handler for ok button click\n * cancel - function-handler for cancel button click. Only for confirm and prompt types\n * time - time (in seconds) after which notification will close (default - 10s)\n * }\n *\n * @param settings\n */\n notifications.notification = function (constructorSettings) {\n\n /** Private vars and methods */\n var notification = null,\n cancel = null,\n type = null,\n confirm = null,\n inputField = null;\n\n var confirmHandler = function () {\n\n close();\n\n if (typeof confirm !== 'function' ) {\n\n return;\n\n }\n\n if (type == 'prompt') {\n\n confirm(inputField.value);\n return;\n\n }\n\n confirm();\n\n };\n\n var cancelHandler = function () {\n\n close();\n\n if (typeof cancel !== 'function' ) {\n\n return;\n\n }\n\n cancel();\n\n };\n\n\n /** Public methods */\n function create(settings) {\n\n if (!(settings && settings.message)) {\n\n editor.core.log('Can\\'t create notification. Message is missed');\n return;\n\n }\n\n settings.type = settings.type || 'alert';\n settings.time = settings.time*1000 || 10000;\n\n var wrapper = editor.draw.node('DIV', 'cdx-notification'),\n message = editor.draw.node('DIV', 'cdx-notification__message'),\n input = editor.draw.node('INPUT', 'cdx-notification__input'),\n okBtn = editor.draw.node('SPAN', 'cdx-notification__ok-btn'),\n cancelBtn = editor.draw.node('SPAN', 'cdx-notification__cancel-btn');\n\n message.textContent = settings.message;\n okBtn.textContent = settings.okMsg || 'ОК';\n cancelBtn.textContent = settings.cancelMsg || 'Отмена';\n\n editor.listeners.add(okBtn, 'click', confirmHandler);\n editor.listeners.add(cancelBtn, 'click', cancelHandler);\n\n wrapper.appendChild(message);\n\n if (settings.type == 'prompt') {\n\n wrapper.appendChild(input);\n\n }\n\n wrapper.appendChild(okBtn);\n\n if (settings.type == 'prompt' || settings.type == 'confirm') {\n\n wrapper.appendChild(cancelBtn);\n\n }\n\n wrapper.classList.add('cdx-notification-' + settings.type);\n wrapper.dataset.type = settings.type;\n\n notification = wrapper;\n type = settings.type;\n confirm = settings.confirm;\n cancel = settings.cancel;\n inputField = input;\n\n if (settings.type != 'prompt' && settings.type != 'confirm') {\n\n window.setTimeout(close, settings.time);\n\n }\n\n };\n\n /**\n * Show notification block\n */\n function send() {\n\n editor.nodes.notifications.appendChild(notification);\n inputField.focus();\n\n editor.nodes.notifications.classList.add('cdx-notification__notification-appending');\n\n window.setTimeout(function () {\n\n editor.nodes.notifications.classList.remove('cdx-notification__notification-appending');\n\n }, 100);\n\n addToQueue({type: type, close: close});\n\n };\n\n /**\n * Remove notification block\n */\n function close() {\n\n notification.remove();\n\n };\n\n\n if (constructorSettings) {\n\n create(constructorSettings);\n send();\n\n }\n\n return {\n create: create,\n send: send,\n close: close\n };\n\n };\n\n notifications.clear = function () {\n\n editor.nodes.notifications.innerHTML = '';\n queue = [];\n\n };\n\n return notifications;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/notifications.js","/**\n * Codex Editor Parser Module\n *\n * @author Codex Team\n * @version 1.1\n */\n\nmodule.exports = (function (parser) {\n\n let editor = codex.editor;\n\n /** inserting text */\n parser.insertPastedContent = function (blockType, tag) {\n\n editor.content.insertBlock({\n type : blockType.type,\n block : blockType.render({\n text : tag.innerHTML\n })\n });\n\n };\n\n /**\n * Check DOM node for display style: separated block or child-view\n */\n parser.isFirstLevelBlock = function (node) {\n\n return node.nodeType == editor.core.nodeTypes.TAG &&\n node.classList.contains(editor.ui.className.BLOCK_CLASSNAME);\n\n };\n\n return parser;\n\n})({});\n\n\n\n// WEBPACK FOOTER //\n// ./modules/parser.js","/**\n * Codex Sanitizer\n */\n\nmodule.exports = (function (sanitizer) {\n\n /** HTML Janitor library */\n let janitor = require('html-janitor');\n\n /** Codex Editor */\n let editor = codex.editor;\n\n sanitizer.prepare = function () {\n\n if (editor.settings.sanitizer && !editor.core.isEmpty(editor.settings.sanitizer)) {\n\n Config.CUSTOM = editor.settings.sanitizer;\n\n }\n\n };\n\n /**\n * Basic config\n */\n var Config = {\n\n /** User configuration */\n CUSTOM : null,\n\n BASIC : {\n\n tags: {\n p: {},\n a: {\n href: true,\n target: '_blank',\n rel: 'nofollow'\n }\n }\n }\n };\n\n sanitizer.Config = Config;\n\n /**\n *\n * @param userCustomConfig\n * @returns {*}\n * @private\n *\n * @description If developer uses editor's API, then he can customize sane restrictions.\n * Or, sane config can be defined globally in editors initialization. That config will be used everywhere\n * At least, if there is no config overrides, that API uses BASIC Default configation\n */\n let init_ = function (userCustomConfig) {\n\n let configuration = userCustomConfig || Config.CUSTOM || Config.BASIC;\n\n return new janitor(configuration);\n\n };\n\n /**\n * Cleans string from unwanted tags\n * @protected\n * @param {String} dirtyString - taint string\n * @param {Object} customConfig - allowed tags\n */\n sanitizer.clean = function (dirtyString, customConfig) {\n\n let janitorInstance = init_(customConfig);\n\n return janitorInstance.clean(dirtyString);\n\n };\n\n return sanitizer;\n\n})({});\n\n\n// WEBPACK FOOTER //\n// ./modules/sanitizer.js","(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n define('html-janitor', factory);\n } else if (typeof exports === 'object') {\n module.exports = factory();\n } else {\n root.HTMLJanitor = factory();\n }\n}(this, function () {\n\n /**\n * @param {Object} config.tags Dictionary of allowed tags.\n * @param {boolean} config.keepNestedBlockElements Default false.\n */\n function HTMLJanitor(config) {\n\n var tagDefinitions = config['tags'];\n var tags = Object.keys(tagDefinitions);\n\n var validConfigValues = tags\n .map(function(k) { return typeof tagDefinitions[k]; })\n .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; });\n\n if(!validConfigValues) {\n throw new Error(\"The configuration was invalid\");\n }\n\n this.config = config;\n }\n\n // TODO: not exhaustive?\n var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE'];\n function isBlockElement(node) {\n return blockElementNames.indexOf(node.nodeName) !== -1;\n }\n\n var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE'];\n function isInlineElement(node) {\n return inlineElementNames.indexOf(node.nodeName) !== -1;\n }\n\n HTMLJanitor.prototype.clean = function (html) {\n var sandbox = document.createElement('div');\n sandbox.innerHTML = html;\n\n this._sanitize(sandbox);\n\n return sandbox.innerHTML;\n };\n\n HTMLJanitor.prototype._sanitize = function (parentNode) {\n var treeWalker = createTreeWalker(parentNode);\n var node = treeWalker.firstChild();\n if (!node) { return; }\n\n do {\n // Ignore nodes that have already been sanitized\n if (node._sanitized) {\n continue;\n }\n\n if (node.nodeType === Node.TEXT_NODE) {\n // If this text node is just whitespace and the previous or next element\n // sibling is a block element, remove it\n // N.B.: This heuristic could change. Very specific to a bug with\n // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output\n // FIXME: make this an option?\n if (node.data.trim() === ''\n && ((node.previousElementSibling && isBlockElement(node.previousElementSibling))\n || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) {\n parentNode.removeChild(node);\n this._sanitize(parentNode);\n break;\n } else {\n continue;\n }\n }\n\n // Remove all comments\n if (node.nodeType === Node.COMMENT_NODE) {\n parentNode.removeChild(node);\n this._sanitize(parentNode);\n break;\n }\n\n var isInline = isInlineElement(node);\n var containsBlockElement;\n if (isInline) {\n containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement);\n }\n\n // Block elements should not be nested (e.g.

  • ...); if\n // they are, we want to unwrap the inner block element.\n var isNotTopContainer = !! parentNode.parentNode;\n var isNestedBlockElement =\n isBlockElement(parentNode) &&\n isBlockElement(node) &&\n isNotTopContainer;\n\n var nodeName = node.nodeName.toLowerCase();\n\n var allowedAttrs = getAllowedAttrs(this.config, nodeName, node);\n\n var isInvalid = isInline && containsBlockElement;\n\n // Drop tag entirely according to the whitelist *and* if the markup\n // is invalid.\n if (isInvalid || shouldRejectNode(node, allowedAttrs)\n || (!this.config.keepNestedBlockElements && isNestedBlockElement)) {\n // Do not keep the inner text of SCRIPT/STYLE elements.\n if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) {\n while (node.childNodes.length > 0) {\n parentNode.insertBefore(node.childNodes[0], node);\n }\n }\n parentNode.removeChild(node);\n\n this._sanitize(parentNode);\n break;\n }\n\n // Sanitize attributes\n for (var a = 0; a < node.attributes.length; a += 1) {\n var attr = node.attributes[a];\n\n if (shouldRejectAttr(attr, allowedAttrs, node)) {\n node.removeAttribute(attr.name);\n // Shift the array to continue looping.\n a = a - 1;\n }\n }\n\n // Sanitize children\n this._sanitize(node);\n\n // Mark node as sanitized so it's ignored in future runs\n node._sanitized = true;\n } while ((node = treeWalker.nextSibling()));\n };\n\n function createTreeWalker(node) {\n return document.createTreeWalker(node,\n NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT,\n null, false);\n }\n\n function getAllowedAttrs(config, nodeName, node){\n if (typeof config.tags[nodeName] === 'function') {\n return config.tags[nodeName](node);\n } else {\n return config.tags[nodeName];\n }\n }\n\n function shouldRejectNode(node, allowedAttrs){\n if (typeof allowedAttrs === 'undefined') {\n return true;\n } else if (typeof allowedAttrs === 'boolean') {\n return !allowedAttrs;\n }\n\n return false;\n }\n\n function shouldRejectAttr(attr, allowedAttrs, node){\n var attrName = attr.name.toLowerCase();\n\n if (allowedAttrs === true){\n return false;\n } else if (typeof allowedAttrs[attrName] === 'function'){\n return !allowedAttrs[attrName](attr.value, node);\n } else if (typeof allowedAttrs[attrName] === 'undefined'){\n return true;\n } else if (allowedAttrs[attrName] === false) {\n return true;\n } else if (typeof allowedAttrs[attrName] === 'string') {\n return (allowedAttrs[attrName] !== attr.value);\n }\n\n return false;\n }\n\n return HTMLJanitor;\n\n}));\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/html-janitor/src/html-janitor.js\n// module id = 17\n// module chunks = 0","/**\n * Codex Editor Listeners module\n *\n * @author Codex Team\n * @version 1.0\n */\n\n/**\n * Module-decorator for event listeners assignment\n */\nmodule.exports = function (listeners) {\n\n var allListeners = [];\n\n /**\n * Search methods\n *\n * byElement, byType and byHandler returns array of suitable listeners\n * one and all takes element, eventType, and handler and returns first (all) suitable listener\n *\n */\n listeners.search = function () {\n\n var byElement = function (element, context) {\n\n var listenersOnElement = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.element === element) {\n\n listenersOnElement.push(listener);\n\n }\n\n }\n\n return listenersOnElement;\n\n };\n\n var byType = function (eventType, context) {\n\n var listenersWithType = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.type === eventType) {\n\n listenersWithType.push(listener);\n\n }\n\n }\n\n return listenersWithType;\n\n };\n\n var byHandler = function (handler, context) {\n\n var listenersWithHandler = [];\n\n context = context || allListeners;\n\n for (var i = 0; i < context.length; i++) {\n\n var listener = context[i];\n\n if (listener.handler === handler) {\n\n listenersWithHandler.push(listener);\n\n }\n\n }\n\n return listenersWithHandler;\n\n };\n\n var one = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result[0];\n\n };\n\n var all = function (element, eventType, handler) {\n\n var result = allListeners;\n\n if (element)\n result = byElement(element, result);\n\n if (eventType)\n result = byType(eventType, result);\n\n if (handler)\n result = byHandler(handler, result);\n\n return result;\n\n };\n\n return {\n byElement : byElement,\n byType : byType,\n byHandler : byHandler,\n one : one,\n all : all\n };\n\n }();\n\n listeners.add = function (element, eventType, handler, isCapture) {\n\n element.addEventListener(eventType, handler, isCapture);\n\n var data = {\n element: element,\n type: eventType,\n handler: handler\n };\n\n var alreadyAddedListener = listeners.search.one(element, eventType, handler);\n\n if (!alreadyAddedListener) {\n\n allListeners.push(data);\n\n }\n\n };\n\n listeners.remove = function (element, eventType, handler) {\n\n element.removeEventListener(eventType, handler);\n\n var existingListeners = listeners.search.all(element, eventType, handler);\n\n for (var i = 0; i < existingListeners.length; i++) {\n\n var index = allListeners.indexOf(existingListeners[i]);\n\n if (index > 0) {\n\n allListeners.splice(index, 1);\n\n }\n\n }\n\n };\n\n listeners.removeAll = function () {\n\n allListeners.map(function (current) {\n\n listeners.remove(current.element, current.type, current.handler);\n\n });\n\n };\n\n listeners.get = function (element, eventType, handler) {\n\n return listeners.search.all(element, eventType, handler);\n\n };\n\n return listeners;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/listeners.js","/**\n * Codex Editor Destroyer module\n *\n * @auhor Codex Team\n * @version 1.0\n */\n\nmodule.exports = function (destroyer) {\n\n let editor = codex.editor;\n\n destroyer.removeNodes = function () {\n\n editor.nodes.wrapper.remove();\n editor.nodes.notifications.remove();\n\n };\n\n destroyer.destroyPlugins = function () {\n\n for (var tool in editor.tools) {\n\n if (typeof editor.tools[tool].destroy === 'function') {\n\n editor.tools[tool].destroy();\n\n }\n\n }\n\n };\n\n destroyer.destroyScripts = function () {\n\n var scripts = document.getElementsByTagName('SCRIPT');\n\n for (var i = 0; i < scripts.length; i++) {\n\n if (scripts[i].id.indexOf(editor.scriptPrefix) + 1) {\n\n scripts[i].remove();\n i--;\n\n }\n\n }\n\n };\n\n\n /**\n * Delete editor data from webpage.\n * You should send settings argument with boolean flags:\n * @param settings.ui- remove redactor event listeners and DOM nodes\n * @param settings.scripts - remove redactor scripts from DOM\n * @param settings.plugins - remove plugin's objects\n * @param settings.core - remove editor core. You can remove core only if UI and scripts flags is true\n * }\n *\n */\n destroyer.destroy = function (settings) {\n\n if (!settings || typeof settings !== 'object') {\n\n return;\n\n }\n\n if (settings.ui) {\n\n destroyer.removeNodes();\n editor.listeners.removeAll();\n\n }\n\n if (settings.scripts) {\n\n destroyer.destroyScripts();\n\n }\n\n if (settings.plugins) {\n\n destroyer.destroyPlugins();\n\n }\n\n if (settings.ui && settings.scripts && settings.core) {\n\n delete codex.editor;\n\n }\n\n };\n\n return destroyer;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/destroyer.js","/**\n * Codex Editor Paste module\n *\n * @author Codex Team\n * @version 1.1.1\n */\n\nmodule.exports = function (paste) {\n\n let editor = codex.editor;\n\n var patterns = [];\n\n paste.prepare = function () {\n\n var tools = editor.tools;\n\n for (var tool in tools) {\n\n if (!tools[tool].renderOnPastePatterns || !Array.isArray(tools[tool].renderOnPastePatterns)) {\n\n continue;\n\n }\n\n tools[tool].renderOnPastePatterns.map(function (pattern) {\n\n\n patterns.push(pattern);\n\n });\n\n }\n\n return Promise.resolve();\n\n };\n\n /**\n * Saves data\n * @param event\n */\n paste.pasted = function (event) {\n\n var clipBoardData = event.clipboardData || window.clipboardData,\n content = clipBoardData.getData('Text');\n\n var result = analize(content);\n\n if (result) {\n\n event.preventDefault();\n event.stopImmediatePropagation();\n\n }\n\n return result;\n\n };\n\n /**\n * Analizes pated string and calls necessary method\n */\n\n var analize = function (string) {\n\n var result = false,\n content = editor.content.currentNode,\n plugin = content.dataset.tool;\n\n patterns.map( function (pattern) {\n\n var execArray = pattern.regex.exec(string),\n match = execArray && execArray[0];\n\n if ( match && match === string.trim()) {\n\n /** current block is not empty */\n if ( content.textContent.trim() && plugin == editor.settings.initialBlockPlugin ) {\n\n pasteToNewBlock_();\n\n }\n\n pattern.callback(string, pattern);\n result = true;\n\n }\n\n });\n\n return result;\n\n };\n\n var pasteToNewBlock_ = function () {\n\n /** Create new initial block */\n editor.content.insertBlock({\n\n type : editor.settings.initialBlockPlugin,\n block : editor.tools[editor.settings.initialBlockPlugin].render({\n text : ''\n })\n\n }, false);\n\n };\n\n /**\n * This method prevents default behaviour.\n *\n * @param {Object} event\n * @protected\n *\n * @description We get from clipboard pasted data, sanitize, make a fragment that contains of this sanitized nodes.\n * Firstly, we need to memorize the caret position. We can do that by getting the range of selection.\n * After all, we insert clear fragment into caret placed position. Then, we should move the caret to the last node\n */\n paste.blockPasteCallback = function (event) {\n\n\n if (!needsToHandlePasteEvent(event.target)) {\n\n return;\n\n }\n\n /** Prevent default behaviour */\n event.preventDefault();\n\n /** get html pasted data - dirty data */\n var htmlData = event.clipboardData.getData('text/html'),\n plainData = event.clipboardData.getData('text/plain');\n\n /** Temporary DIV that is used to work with text's paragraphs as DOM-elements*/\n var paragraphs = editor.draw.node('DIV', '', {}),\n cleanData,\n wrappedData;\n\n /** Create fragment, that we paste to range after proccesing */\n cleanData = editor.sanitizer.clean(htmlData);\n\n /**\n * We wrap pasted text with

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

    ) whit content, that should be inserted\n */\n var insertPastedParagraphs = function (paragraphs) {\n\n var NEW_BLOCK_TYPE = editor.settings.initialBlockPlugin,\n currentNode = editor.content.currentNode;\n\n\n paragraphs.forEach(function (paragraph) {\n\n /** Don't allow empty paragraphs */\n if (editor.core.isBlockEmpty(paragraph)) {\n\n return;\n\n }\n\n editor.content.insertBlock({\n type : NEW_BLOCK_TYPE,\n block : editor.tools[NEW_BLOCK_TYPE].render({\n text : paragraph.innerHTML\n })\n });\n\n editor.caret.inputIndex++;\n\n });\n\n editor.caret.setToPreviousBlock(editor.caret.getCurrentInputIndex() + 1);\n\n\n /**\n * If there was no data in working node, remove it\n */\n if (editor.core.isBlockEmpty(currentNode)) {\n\n currentNode.remove();\n editor.ui.saveInputs();\n\n }\n\n\n };\n\n /**\n * Inserts node content at the caret position\n *\n * @param {Node} node - DOM node (could be DocumentFragment), that should be inserted at the caret location\n */\n var emulateUserAgentBehaviour = function (node) {\n\n var newNode;\n\n if (node.childElementCount) {\n\n newNode = document.createDocumentFragment();\n\n node.childNodes.forEach(function (current) {\n\n if (!editor.core.isDomNode(current) && current.data.trim() === '') {\n\n return;\n\n }\n\n newNode.appendChild(current.cloneNode(true));\n\n });\n\n } else {\n\n newNode = document.createTextNode(node.textContent);\n\n }\n\n editor.caret.insertNode(newNode);\n\n };\n\n\n return paste;\n\n}({});\n\n\n// WEBPACK FOOTER //\n// ./modules/paste.js"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///webpack/bootstrap 74eb0b2777970a23ebde","webpack:///./codex.js","webpack:///./src/modules/core.js"],"names":["module","exports","config","configuration","moduleInstances","eventsDispatcher","Events","init","core","require","eventDispatcher","subscribers","eventName","callback","push","data","reduce","previousData","currentHandler","on","console","log","emit"],"mappings":";;AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,uBAAe;AACf;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;;;;;;;;;;;;ACtCA;;;;;;;;AAQAA,QAAOC,OAAP;AAAA;AAAA;;;AAEI;AAFJ,6BAGyB;;AAEjB,oBAAO,SAAP;AAEH;;AAED;;AATJ;AAAA;AAAA,6BAU8B;;AAEtB,oBAAO,aAAP;AAEH;;AAED;;;;;;;AAhBJ;;AAsBI,0BAAYC,MAAZ,EAAoB;;AAEhB;;AAFgB;;AAIhB,cAAKC,aAAL,GAAqBD,MAArB;AACA,cAAKE,eAAL,GAAuB,EAAvB;;AAEA,cAAKC,gBAAL,GAAwB,IAAIC,MAAJ,EAAxB;;AAEA,cAAKC,IAAL;AAEH;;AAED;;;;;;;AAnCJ;AAAA;AAAA,gCAwCW;;AAEH,iBAAIC,OAAkB,mBAAAC,CAAQ,EAAR,CAAtB;AACI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEJ,kBAAKL,eAAL,CAAqB,MAArB,IAA0C,IAAII,IAAJ,CAAS,EAAEE,iBAAkB,KAAKL,gBAAzB,EAAT,CAA1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEH;AA5EL;;AAAA;AAAA;;KAiFMC,M;AAEF,uBAAc;AAAA;;AAEV,cAAKK,WAAL,GAAmB,EAAnB;AAEH;;;;4BAEEC,S,EAAWC,Q,EAAU;;AAEpB,iBAAI,EAAED,aAAa,KAAKD,WAApB,CAAJ,EAAsC;;AAElC,sBAAKA,WAAL,CAAiBC,SAAjB,IAA8B,EAA9B;AAEH;;AAED;AACA,kBAAKD,WAAL,CAAiBC,SAAjB,EAA4BE,IAA5B,CAAiCD,QAAjC;AAEH;;;8BAEID,S,EAAWG,I,EAAM;;AAElB,kBAAKJ,WAAL,CAAiBC,SAAjB,EAA4BI,MAA5B,CAAmC,UAAUC,YAAV,EAAwBC,cAAxB,EAAwC;;AAEvEA,gCAAeD,YAAf;AACA,wBAAOA,YAAP;AAEH,cALD,EAKGF,IALH;AAOH;;;;;AAGL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,W;;;;;;;;;;;;;ACpQA;;;;;;;AAOAf,QAAOC,OAAP;AAEI,yBAAgC;AAAA,aAAlBS,eAAkB,QAAlBA,eAAkB;;AAAA;;AAE5B,cAAKA,eAAL,GAAuBA,eAAvB;AACA,cAAKK,IAAL,GAAY,CAAC,CAAD,EAAI,CAAJ,EAAO,CAAP,CAAZ;AACA,cAAKR,IAAL;AAEH;;AARL;AAAA;AAAA,gCAUW;;AAEH,kBAAKG,eAAL,CAAqBS,EAArB,CAAwB,uBAAxB,EAAiD,UAAUJ,IAAV,EAAgB;;AAE7DK,yBAAQC,GAAR,CAAY,6CAAZ;AAEH,cAJD;;AAMA,kBAAKX,eAAL,CAAqBY,IAArB,CAA0B,uBAA1B,EAAmD,KAAKP,IAAxD;AAEH;AApBL;;AAAA;AAAA;AAuBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,W","file":"codex-editor.js","sourcesContent":[" \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 74eb0b2777970a23ebde","/**\n * Codex Editor\n *\n *\n *\n *\n * @author CodeX Team\n */\nmodule.exports = class CodexEditor {\n\n /** Editor version */\n static get version() {\n\n return VERSION;\n\n }\n\n /** Editor script prefixes */\n static get scriptPrefix() {\n\n return 'cdx-script-';\n\n }\n\n /**\n * @param config\n *\n * @property this.configuration - editor instance configuration\n * @property this.moduleInstances - editor module instances\n */\n constructor(config) {\n\n 'use strict';\n\n this.configuration = config;\n this.moduleInstances = [];\n\n this.eventsDispatcher = new Events();\n\n this.init();\n\n }\n\n /**\n * Initializes modules:\n * First: requiring modules from path\n * Second: memorizing the instances\n */\n init() {\n\n let core = require('./src/modules/core');\n // tools = require('./src/modules/tools'),\n // transport = require('./src/modules/transport'),\n // renderer = require('./src/modules/renderer'),\n // saver = require('./src/modules/saver'),\n // content = require('./src/modules/content'),\n // toolbar = require('./src/modules/toolbar/toolbar'),\n // callbacks = require('./src/modules/callbacks'),\n // draw = require('./src/modules/draw'),\n // caret = require('./src/modules/caret'),\n // notifications = require('./src/modules/notifications'),\n // parser = require('./src/modules/parser'),\n // sanitizer = require('./src/modules/sanitizer'),\n // listeners = require('./src/modules/listeners'),\n // destroyer = require('./src/modules/destroyer'),\n // paste = require('./src/modules/paste');\n\n this.moduleInstances['core'] = new core({ eventDispatcher : this.eventsDispatcher});\n // this.moduleInstances['tools'] = tools;\n // this.moduleInstances['transport'] = transport;\n // this.moduleInstances['renderer'] = renderer;\n // this.moduleInstances['saver'] = saver;\n // this.moduleInstances['content'] = content;\n // this.moduleInstances['toolbar'] = toolbar;\n // this.moduleInstances['callbacks'] = callbacks;\n // this.moduleInstances['draw'] = draw;\n // this.moduleInstances['caret'] = caret;\n // this.moduleInstances['notifications'] = notifications;\n // this.moduleInstances['parser'] = parser;\n // this.moduleInstances['sanitizer'] = sanitizer;\n // this.moduleInstances['listeners'] = listeners;\n // this.moduleInstances['destroyer'] = destroyer;\n // this.moduleInstances['paste'] = paste;\n\n }\n\n\n};\n\nclass Events {\n\n constructor() {\n\n this.subscribers = {};\n\n }\n\n on(eventName, callback) {\n\n if (!(eventName in this.subscribers)) {\n\n this.subscribers[eventName] = [];\n\n }\n\n // group by events\n this.subscribers[eventName].push(callback);\n\n }\n\n emit(eventName, data) {\n\n this.subscribers[eventName].reduce(function (previousData, currentHandler) {\n\n currentHandler(previousData);\n return previousData;\n\n }, data);\n\n }\n\n}\n// module.exports = (function (editor) {\n//\n// 'use strict';\n//\n// editor.version = VERSION;\n// editor.scriptPrefix = 'cdx-script-';\n//\n// var init = function () {\n//\n// editor.core = require('./modules/core');\n// editor.tools = require('./modules/tools');\n// editor.ui = require('./modules/ui');\n// editor.transport = require('./modules/transport');\n// editor.renderer = require('./modules/renderer');\n// editor.saver = require('./modules/saver');\n// editor.content = require('./modules/content');\n// editor.toolbar = require('./modules/toolbar/toolbar');\n// editor.callback = require('./modules/callbacks');\n// editor.draw = require('./modules/draw');\n// editor.caret = require('./modules/caret');\n// editor.notifications = require('./modules/notifications');\n// editor.parser = require('./modules/parser');\n// editor.sanitizer = require('./modules/sanitizer');\n// editor.listeners = require('./modules/listeners');\n// editor.destroyer = require('./modules/destroyer');\n// editor.paste = require('./modules/paste');\n//\n// };\n//\n// /**\n// * @public\n// * holds initial settings\n// */\n// editor.settings = {\n// tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n// holderId : 'codex-editor',\n//\n// // Type of block showing on empty editor\n// initialBlockPlugin: 'paragraph'\n// };\n//\n// /**\n// * public\n// *\n// * Static nodes\n// */\n// editor.nodes = {\n// holder : null,\n// wrapper : null,\n// toolbar : null,\n// inlineToolbar : {\n// wrapper : null,\n// buttons : null,\n// actions : null\n// },\n// toolbox : null,\n// notifications : null,\n// plusButton : null,\n// showSettingsButton: null,\n// showTrashButton : null,\n// blockSettings : null,\n// pluginSettings : null,\n// defaultSettings : null,\n// toolbarButtons : {}, // { type : DomEl, ... }\n// redactor : null\n// };\n//\n// /**\n// * @public\n// *\n// * Output state\n// */\n// editor.state = {\n// jsonOutput : [],\n// blocks : [],\n// inputs : []\n// };\n//\n// /**\n// * @public\n// * Editor plugins\n// */\n// editor.tools = {};\n//\n// /**\n// * Initialization\n// * @uses Promise cEditor.core.prepare\n// * @param {Object} userSettings\n// * @param {Array} userSettings.tools list of plugins\n// * @param {String} userSettings.holderId Element's id to append editor\n// *\n// * Load user defined tools\n// * Tools must contain this important objects :\n// * @param {String} type - this is a type of plugin. It can be used as plugin name\n// * @param {String} iconClassname - this a icon in toolbar\n// * @param {Object} make - what should plugin do, when it is clicked\n// * @param {Object} appendCallback - callback after clicking\n// * @param {Element} settings - what settings does it have\n// * @param {Object} render - plugin get JSON, and should return HTML\n// * @param {Object} save - plugin gets HTML content, returns JSON\n// * @param {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\n// * @param {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\n// *\n// * @example\n// * - type : 'header',\n// * - iconClassname : 'ce-icon-header',\n// * - make : headerTool.make,\n// * - appendCallback : headerTool.appendCallback,\n// * - settings : headerTool.makeSettings(),\n// * - render : headerTool.render,\n// * - save : headerTool.save,\n// * - displayInToolbox : true,\n// * - enableLineBreaks : false\n// */\n// editor.start = function (userSettings) {\n//\n// init();\n//\n// editor.core.prepare(userSettings)\n//\n// // If all ok, make UI, bind events and parse initial-content\n// .then(editor.ui.prepare)\n// .then(editor.tools.prepare)\n// .then(editor.sanitizer.prepare)\n// .then(editor.paste.prepare)\n// .then(editor.transport.prepare)\n// .then(editor.renderer.makeBlocksFromData)\n// .then(editor.ui.saveInputs)\n// .catch(function (error) {\n//\n// editor.core.log('Initialization failed with error: %o', 'warn', error);\n//\n// });\n//\n// };\n//\n// return editor;\n//\n// })({});\n\n\n\n// WEBPACK FOOTER //\n// ./codex.js","/**\n * Codex Editor Core\n *\n * @author Codex Team\n * @version 1.1.3\n */\n\nmodule.exports = class Core {\n\n constructor({ eventDispatcher}) {\n\n this.eventDispatcher = eventDispatcher;\n this.data = [1, 2, 3];\n this.init();\n\n }\n\n init() {\n\n this.eventDispatcher.on('Editor proccessing...', function (data) {\n\n console.log('Function fired when editor started proccess');\n\n });\n\n this.eventDispatcher.emit('Editor proccessing...', this.data);\n\n }\n\n};\n// module.exports = (function (core) {\n//\n// let editor = codex.editor;\n//\n// /**\n// * @public\n// *\n// * Editor preparing method\n// * @return Promise\n// */\n// core.prepare = function (userSettings) {\n//\n// return new Promise(function (resolve, reject) {\n//\n// if ( userSettings ) {\n//\n// editor.settings.tools = userSettings.tools || editor.settings.tools;\n//\n// }\n//\n// if (userSettings.data) {\n//\n// editor.state.blocks = userSettings.data;\n//\n// }\n//\n// if (userSettings.initialBlockPlugin) {\n//\n// editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin;\n//\n// }\n//\n// if (userSettings.sanitizer) {\n//\n// editor.settings.sanitizer = userSettings.sanitizer;\n//\n// }\n//\n// editor.hideToolbar = userSettings.hideToolbar;\n//\n// editor.settings.placeholder = userSettings.placeholder || '';\n//\n// editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId);\n//\n// if (typeof editor.nodes.holder === undefined || editor.nodes.holder === null) {\n//\n// reject(Error(\"Holder wasn't found by ID: #\" + userSettings.holderId));\n//\n// } else {\n//\n// resolve();\n//\n// }\n//\n// });\n//\n// };\n//\n// /**\n// * Logging method\n// * @param type = ['log', 'info', 'warn']\n// */\n// core.log = function (msg, type, arg) {\n//\n// type = type || 'log';\n//\n// if (!arg) {\n//\n// arg = msg || 'undefined';\n// msg = '[codex-editor]: %o';\n//\n// } else {\n//\n// msg = '[codex-editor]: ' + msg;\n//\n// }\n//\n// try{\n//\n// if ( 'console' in window && window.console[ type ] ) {\n//\n// if ( arg ) window.console[ type ]( msg, arg );\n// else window.console[ type ]( msg );\n//\n// }\n//\n// }catch(e) {}\n//\n// };\n//\n// /**\n// * @protected\n// *\n// * Helper for insert one element after another\n// */\n// core.insertAfter = function (target, element) {\n//\n// target.parentNode.insertBefore(element, target.nextSibling);\n//\n// };\n//\n// /**\n// * @const\n// *\n// * Readable DOM-node types map\n// */\n// core.nodeTypes = {\n// TAG : 1,\n// TEXT : 3,\n// COMMENT : 8,\n// DOCUMENT_FRAGMENT: 11\n// };\n//\n// /**\n// * @const\n// * Readable keys map\n// */\n// core.keys = { BACKSPACE: 8, TAB: 9, ENTER: 13, SHIFT: 16, CTRL: 17, ALT: 18, ESC: 27, SPACE: 32, LEFT: 37, UP: 38, DOWN: 40, RIGHT: 39, DELETE: 46, META: 91 };\n//\n// /**\n// * @protected\n// *\n// * Check object for DOM node\n// */\n// core.isDomNode = function (el) {\n//\n// return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG;\n//\n// };\n//\n// /**\n// * Checks passed object for emptiness\n// * @require ES5 - Object.keys\n// * @param {object}\n// */\n// core.isEmpty = function ( obj ) {\n//\n// return Object.keys(obj).length === 0;\n//\n// };\n//\n// /**\n// * Native Ajax\n// * @param {String} settings.url - request URL\n// * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks\n// * @param {function} settings.success\n// * @param {function} settings.progress\n// */\n// core.ajax = function (settings) {\n//\n// if (!settings || !settings.url) {\n//\n// return;\n//\n// }\n//\n// var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'),\n// encodedString,\n// isFormData,\n// prop;\n//\n//\n// settings.async = true;\n// settings.type = settings.type || 'GET';\n// settings.data = settings.data || '';\n// settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8';\n//\n// if (settings.type == 'GET' && settings.data) {\n//\n// settings.url = /\\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data;\n//\n// } else {\n//\n// encodedString = '';\n// for(prop in settings.data) {\n//\n// encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&');\n//\n// }\n//\n// }\n//\n// if (settings.withCredentials) {\n//\n// XMLHTTP.withCredentials = true;\n//\n// }\n//\n// /**\n// * Value returned in beforeSend funtion will be passed as context to the other response callbacks\n// * If beforeSend returns false, AJAX will be blocked\n// */\n// let responseContext,\n// beforeSendResult;\n//\n// if (typeof settings.beforeSend === 'function') {\n//\n// beforeSendResult = settings.beforeSend.call();\n//\n// if (beforeSendResult === false) {\n//\n// return;\n//\n// }\n//\n// }\n//\n// XMLHTTP.open( settings.type, settings.url, settings.async );\n//\n// /**\n// * If we send FormData, we need no content-type header\n// */\n// isFormData = isFormData_(settings.data);\n//\n// if (!isFormData) {\n//\n// if (settings.type !== 'POST') {\n//\n// XMLHTTP.setRequestHeader('Content-type', settings['content-type']);\n//\n// } else {\n//\n// XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');\n//\n// }\n//\n// }\n//\n// XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\n//\n// responseContext = beforeSendResult || XMLHTTP;\n//\n// if (typeof settings.progress === 'function') {\n//\n// XMLHTTP.upload.onprogress = settings.progress.bind(responseContext);\n//\n// }\n//\n// XMLHTTP.onreadystatechange = function () {\n//\n// if (XMLHTTP.readyState === 4) {\n//\n// if (XMLHTTP.status === 200) {\n//\n// if (typeof settings.success === 'function') {\n//\n// settings.success.call(responseContext, XMLHTTP.responseText);\n//\n// }\n//\n// } else {\n//\n// if (typeof settings.error === 'function') {\n//\n// settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status);\n//\n// }\n//\n// }\n//\n// }\n//\n// };\n//\n// if (isFormData) {\n//\n// // Sending FormData\n// XMLHTTP.send(settings.data);\n//\n// } else {\n//\n// // POST requests\n// XMLHTTP.send(encodedString);\n//\n// }\n//\n// return XMLHTTP;\n//\n// };\n//\n// /**\n// * Appends script to head of document\n// * @return Promise\n// */\n// core.importScript = function (scriptPath, instanceName) {\n//\n// return new Promise(function (resolve, reject) {\n//\n// let script;\n//\n// /** Script is already loaded */\n// if ( !instanceName ) {\n//\n// reject('Instance name is missed');\n//\n// } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) {\n//\n// resolve(scriptPath);\n//\n// }\n//\n// script = document.createElement('SCRIPT');\n// script.async = true;\n// script.defer = true;\n// script.id = editor.scriptPrefix + instanceName;\n//\n// script.onload = function () {\n//\n// resolve(scriptPath);\n//\n// };\n//\n// script.onerror = function () {\n//\n// reject(scriptPath);\n//\n// };\n//\n// script.src = scriptPath;\n// document.head.appendChild(script);\n//\n// });\n//\n// };\n//\n// /**\n// * Function for checking is it FormData object to send.\n// * @param {Object} object to check\n// * @return boolean\n// */\n// var isFormData_ = function (object) {\n//\n// return object instanceof FormData;\n//\n// };\n//\n// /**\n// * Check block\n// * @param target\n// * @description Checks target is it native input\n// */\n// core.isNativeInput = function (target) {\n//\n// var nativeInputAreas = ['INPUT', 'TEXTAREA'];\n//\n// return nativeInputAreas.indexOf(target.tagName) != -1;\n//\n// };\n//\n// /**\n// * Check if block is empty\n// * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME\n// *\n// * @param block\n// * @returns {boolean}\n// */\n// core.isBlockEmpty = function (block) {\n//\n// const EXCEPTION_TAGS = ['IMG', 'IFRAME'];\n//\n// var nativeInputs = block.querySelectorAll('textarea, input'),\n// nativeInputsAreEmpty = true,\n// textContentIsEmpty = !block.textContent.trim();\n//\n// Array.prototype.forEach.call(nativeInputs, function (input) {\n//\n// if (input.type == 'textarea' || input.type == 'text') {\n//\n// nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim();\n//\n// }\n//\n// });\n//\n// return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName);\n//\n// };\n//\n//\n// return core;\n//\n// })({});\n\n\n\n// WEBPACK FOOTER //\n// ./src/modules/core.js"],"sourceRoot":""} \ No newline at end of file diff --git a/codex.js b/codex.js index 4607a8a3..bb7cb4a7 100644 --- a/codex.js +++ b/codex.js @@ -1,8 +1,10 @@ /** - * * Codex Editor * - * @author Codex Team + * + * + * + * @author CodeX Team */ module.exports = class CodexEditor { @@ -24,36 +26,18 @@ module.exports = class CodexEditor { * @param config * * @property this.configuration - editor instance configuration - * @property this.instances - editor module instances + * @property this.moduleInstances - editor module instances */ constructor(config) { 'use strict'; this.configuration = config; - this.instances = []; + this.moduleInstances = []; - let modules = [ - 'core', - 'tools', - 'transport', - 'renderer', - 'saver', - 'content', - 'toolbar/toolbar', - 'callbacks', - 'draw', - 'caret', - 'notifications', - 'parser', - 'sanitizer', - 'listeners', - 'destroyer', - 'paste' - ], - modulePath = './modules/'; + this.eventsDispatcher = new Events(); - this.init(modulePath); + this.init(); } @@ -61,39 +45,81 @@ module.exports = class CodexEditor { * Initializes modules: * First: requiring modules from path * Second: memorizing the instances - * - * @param {String} module name - * @param {String} module path */ - init(path) { + init() { - let core = require('./modules/core'), - tools = require('./modules/tools'), - transport = require('./modules/transport'), - renderer = require('./modules/renderer'), - saver = require('./modules/saver'), - content = require('./modules/content'), - toolbar = require('./modules/toolbar/toolbar'), - callbacks = require('./modules/callbacks'), - draw = require('./modules/draw'), - caret = require('./modules/caret'), - notifications = require('./modules/notifications'), - parser = require('./modules/parser'), - sanitizer = require('./modules/sanitizer'), - listeners = require('./modules/listeners'), - destroyer = require('./modules/destroyer'), - paste = require('./modules/paste'); + let core = require('./src/modules/core'); + // tools = require('./src/modules/tools'), + // transport = require('./src/modules/transport'), + // renderer = require('./src/modules/renderer'), + // saver = require('./src/modules/saver'), + // content = require('./src/modules/content'), + // toolbar = require('./src/modules/toolbar/toolbar'), + // callbacks = require('./src/modules/callbacks'), + // draw = require('./src/modules/draw'), + // caret = require('./src/modules/caret'), + // notifications = require('./src/modules/notifications'), + // parser = require('./src/modules/parser'), + // sanitizer = require('./src/modules/sanitizer'), + // listeners = require('./src/modules/listeners'), + // destroyer = require('./src/modules/destroyer'), + // paste = require('./src/modules/paste'); - this.instances['core'] = core; - this.instances['tools'] = tools; - - - console.log('Class', this); + this.moduleInstances['core'] = new core({ eventDispatcher : this.eventsDispatcher}); + // this.moduleInstances['tools'] = tools; + // this.moduleInstances['transport'] = transport; + // this.moduleInstances['renderer'] = renderer; + // this.moduleInstances['saver'] = saver; + // this.moduleInstances['content'] = content; + // this.moduleInstances['toolbar'] = toolbar; + // this.moduleInstances['callbacks'] = callbacks; + // this.moduleInstances['draw'] = draw; + // this.moduleInstances['caret'] = caret; + // this.moduleInstances['notifications'] = notifications; + // this.moduleInstances['parser'] = parser; + // this.moduleInstances['sanitizer'] = sanitizer; + // this.moduleInstances['listeners'] = listeners; + // this.moduleInstances['destroyer'] = destroyer; + // this.moduleInstances['paste'] = paste; } }; + +class Events { + + constructor() { + + this.subscribers = {}; + + } + + on(eventName, callback) { + + if (!(eventName in this.subscribers)) { + + this.subscribers[eventName] = []; + + } + + // group by events + this.subscribers[eventName].push(callback); + + } + + emit(eventName, data) { + + this.subscribers[eventName].reduce(function (previousData, currentHandler) { + + currentHandler(previousData); + return previousData; + + }, data); + + } + +} // module.exports = (function (editor) { // // 'use strict'; diff --git a/example.html b/example.html index 334bf4a7..020c96f4 100644 --- a/example.html +++ b/example.html @@ -64,10 +64,10 @@ inittialBlock : 'paragraph' }); - var editor2 = new CodexEditor({ - holderId : 'cdx', - initialBlock: 'header' - }); +// var editor2 = new CodexEditor({ +// holderId : 'cdx', +// initialBlock: 'header' +// }); // codex.editor.start({ // holderId : "codex-editor", // initialBlockPlugin : 'paragraph', diff --git a/modules/core.js b/modules/core.js deleted file mode 100644 index ad4a08b8..00000000 --- a/modules/core.js +++ /dev/null @@ -1,389 +0,0 @@ -/** - * Codex Editor Core - * - * @author Codex Team - * @version 1.1.3 - */ - -module.exports = (function (core) { - - let editor = codex.editor; - - /** - * @public - * - * Editor preparing method - * @return Promise - */ - core.prepare = function (userSettings) { - - return new Promise(function (resolve, reject) { - - if ( userSettings ) { - - editor.settings.tools = userSettings.tools || editor.settings.tools; - - } - - if (userSettings.data) { - - editor.state.blocks = userSettings.data; - - } - - if (userSettings.initialBlockPlugin) { - - editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin; - - } - - if (userSettings.sanitizer) { - - editor.settings.sanitizer = userSettings.sanitizer; - - } - - editor.hideToolbar = userSettings.hideToolbar; - - editor.settings.placeholder = userSettings.placeholder || ''; - - editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId); - - if (typeof editor.nodes.holder === undefined || editor.nodes.holder === null) { - - reject(Error("Holder wasn't found by ID: #" + userSettings.holderId)); - - } else { - - resolve(); - - } - - }); - - }; - - /** - * Logging method - * @param type = ['log', 'info', 'warn'] - */ - core.log = function (msg, type, arg) { - - type = type || 'log'; - - if (!arg) { - - arg = msg || 'undefined'; - msg = '[codex-editor]: %o'; - - } else { - - msg = '[codex-editor]: ' + msg; - - } - - try{ - - if ( 'console' in window && window.console[ type ] ) { - - if ( arg ) window.console[ type ]( msg, arg ); - else window.console[ type ]( msg ); - - } - - }catch(e) {} - - }; - - /** - * @protected - * - * Helper for insert one element after another - */ - core.insertAfter = function (target, element) { - - target.parentNode.insertBefore(element, target.nextSibling); - - }; - - /** - * @const - * - * Readable DOM-node types map - */ - core.nodeTypes = { - TAG : 1, - TEXT : 3, - COMMENT : 8, - DOCUMENT_FRAGMENT: 11 - }; - - /** - * @const - * Readable keys map - */ - 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 }; - - /** - * @protected - * - * Check object for DOM node - */ - core.isDomNode = function (el) { - - return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG; - - }; - - /** - * Checks passed object for emptiness - * @require ES5 - Object.keys - * @param {object} - */ - core.isEmpty = function ( obj ) { - - return Object.keys(obj).length === 0; - - }; - - /** - * Native Ajax - * @param {String} settings.url - request URL - * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks - * @param {function} settings.success - * @param {function} settings.progress - */ - core.ajax = function (settings) { - - if (!settings || !settings.url) { - - return; - - } - - var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'), - encodedString, - isFormData, - prop; - - - settings.async = true; - settings.type = settings.type || 'GET'; - settings.data = settings.data || ''; - settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8'; - - if (settings.type == 'GET' && settings.data) { - - settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data; - - } else { - - encodedString = ''; - for(prop in settings.data) { - - encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&'); - - } - - } - - if (settings.withCredentials) { - - XMLHTTP.withCredentials = true; - - } - - /** - * Value returned in beforeSend funtion will be passed as context to the other response callbacks - * If beforeSend returns false, AJAX will be blocked - */ - let responseContext, - beforeSendResult; - - if (typeof settings.beforeSend === 'function') { - - beforeSendResult = settings.beforeSend.call(); - - if (beforeSendResult === false) { - - return; - - } - - } - - XMLHTTP.open( settings.type, settings.url, settings.async ); - - /** - * If we send FormData, we need no content-type header - */ - isFormData = isFormData_(settings.data); - - if (!isFormData) { - - if (settings.type !== 'POST') { - - XMLHTTP.setRequestHeader('Content-type', settings['content-type']); - - } else { - - XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - - } - - } - - XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - - responseContext = beforeSendResult || XMLHTTP; - - if (typeof settings.progress === 'function') { - - XMLHTTP.upload.onprogress = settings.progress.bind(responseContext); - - } - - XMLHTTP.onreadystatechange = function () { - - if (XMLHTTP.readyState === 4) { - - if (XMLHTTP.status === 200) { - - if (typeof settings.success === 'function') { - - settings.success.call(responseContext, XMLHTTP.responseText); - - } - - } else { - - if (typeof settings.error === 'function') { - - settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status); - - } - - } - - } - - }; - - if (isFormData) { - - // Sending FormData - XMLHTTP.send(settings.data); - - } else { - - // POST requests - XMLHTTP.send(encodedString); - - } - - return XMLHTTP; - - }; - - /** - * Appends script to head of document - * @return Promise - */ - core.importScript = function (scriptPath, instanceName) { - - return new Promise(function (resolve, reject) { - - let script; - - /** Script is already loaded */ - if ( !instanceName ) { - - reject('Instance name is missed'); - - } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) { - - resolve(scriptPath); - - } - - script = document.createElement('SCRIPT'); - script.async = true; - script.defer = true; - script.id = editor.scriptPrefix + instanceName; - - script.onload = function () { - - resolve(scriptPath); - - }; - - script.onerror = function () { - - reject(scriptPath); - - }; - - script.src = scriptPath; - document.head.appendChild(script); - - }); - - }; - - /** - * Function for checking is it FormData object to send. - * @param {Object} object to check - * @return boolean - */ - var isFormData_ = function (object) { - - return object instanceof FormData; - - }; - - /** - * Check block - * @param target - * @description Checks target is it native input - */ - core.isNativeInput = function (target) { - - var nativeInputAreas = ['INPUT', 'TEXTAREA']; - - return nativeInputAreas.indexOf(target.tagName) != -1; - - }; - - /** - * Check if block is empty - * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME - * - * @param block - * @returns {boolean} - */ - core.isBlockEmpty = function (block) { - - const EXCEPTION_TAGS = ['IMG', 'IFRAME']; - - var nativeInputs = block.querySelectorAll('textarea, input'), - nativeInputsAreEmpty = true, - textContentIsEmpty = !block.textContent.trim(); - - Array.prototype.forEach.call(nativeInputs, function (input) { - - if (input.type == 'textarea' || input.type == 'text') { - - nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim(); - - } - - }); - - return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName); - - }; - - - return core; - -})({}); diff --git a/modules/anchors.js b/src/modules/anchors.js similarity index 100% rename from modules/anchors.js rename to src/modules/anchors.js diff --git a/modules/callbacks.js b/src/modules/callbacks.js similarity index 100% rename from modules/callbacks.js rename to src/modules/callbacks.js diff --git a/modules/caret.js b/src/modules/caret.js similarity index 100% rename from modules/caret.js rename to src/modules/caret.js diff --git a/modules/content.js b/src/modules/content.js similarity index 100% rename from modules/content.js rename to src/modules/content.js diff --git a/src/modules/core.js b/src/modules/core.js new file mode 100644 index 00000000..510ada9c --- /dev/null +++ b/src/modules/core.js @@ -0,0 +1,412 @@ +/** + * Codex Editor Core + * + * @author Codex Team + * @version 1.1.3 + */ + +module.exports = class Core { + + constructor({ eventDispatcher}) { + + this.eventDispatcher = eventDispatcher; + this.data = [1, 2, 3]; + this.init(); + + } + + init() { + + this.eventDispatcher.on('Editor proccessing...', function (data) { + + console.log('Function fired when editor started proccess'); + + }); + + this.eventDispatcher.emit('Editor proccessing...', this.data); + + } + +}; +// module.exports = (function (core) { +// +// let editor = codex.editor; +// +// /** +// * @public +// * +// * Editor preparing method +// * @return Promise +// */ +// core.prepare = function (userSettings) { +// +// return new Promise(function (resolve, reject) { +// +// if ( userSettings ) { +// +// editor.settings.tools = userSettings.tools || editor.settings.tools; +// +// } +// +// if (userSettings.data) { +// +// editor.state.blocks = userSettings.data; +// +// } +// +// if (userSettings.initialBlockPlugin) { +// +// editor.settings.initialBlockPlugin = userSettings.initialBlockPlugin; +// +// } +// +// if (userSettings.sanitizer) { +// +// editor.settings.sanitizer = userSettings.sanitizer; +// +// } +// +// editor.hideToolbar = userSettings.hideToolbar; +// +// editor.settings.placeholder = userSettings.placeholder || ''; +// +// editor.nodes.holder = document.getElementById(userSettings.holderId || editor.settings.holderId); +// +// if (typeof editor.nodes.holder === undefined || editor.nodes.holder === null) { +// +// reject(Error("Holder wasn't found by ID: #" + userSettings.holderId)); +// +// } else { +// +// resolve(); +// +// } +// +// }); +// +// }; +// +// /** +// * Logging method +// * @param type = ['log', 'info', 'warn'] +// */ +// core.log = function (msg, type, arg) { +// +// type = type || 'log'; +// +// if (!arg) { +// +// arg = msg || 'undefined'; +// msg = '[codex-editor]: %o'; +// +// } else { +// +// msg = '[codex-editor]: ' + msg; +// +// } +// +// try{ +// +// if ( 'console' in window && window.console[ type ] ) { +// +// if ( arg ) window.console[ type ]( msg, arg ); +// else window.console[ type ]( msg ); +// +// } +// +// }catch(e) {} +// +// }; +// +// /** +// * @protected +// * +// * Helper for insert one element after another +// */ +// core.insertAfter = function (target, element) { +// +// target.parentNode.insertBefore(element, target.nextSibling); +// +// }; +// +// /** +// * @const +// * +// * Readable DOM-node types map +// */ +// core.nodeTypes = { +// TAG : 1, +// TEXT : 3, +// COMMENT : 8, +// DOCUMENT_FRAGMENT: 11 +// }; +// +// /** +// * @const +// * Readable keys map +// */ +// 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 }; +// +// /** +// * @protected +// * +// * Check object for DOM node +// */ +// core.isDomNode = function (el) { +// +// return el && typeof el === 'object' && el.nodeType && el.nodeType == this.nodeTypes.TAG; +// +// }; +// +// /** +// * Checks passed object for emptiness +// * @require ES5 - Object.keys +// * @param {object} +// */ +// core.isEmpty = function ( obj ) { +// +// return Object.keys(obj).length === 0; +// +// }; +// +// /** +// * Native Ajax +// * @param {String} settings.url - request URL +// * @param {function} settings.beforeSend - returned value will be passed as context to the Success, Error and Progress callbacks +// * @param {function} settings.success +// * @param {function} settings.progress +// */ +// core.ajax = function (settings) { +// +// if (!settings || !settings.url) { +// +// return; +// +// } +// +// var XMLHTTP = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'), +// encodedString, +// isFormData, +// prop; +// +// +// settings.async = true; +// settings.type = settings.type || 'GET'; +// settings.data = settings.data || ''; +// settings['content-type'] = settings['content-type'] || 'application/json; charset=utf-8'; +// +// if (settings.type == 'GET' && settings.data) { +// +// settings.url = /\?/.test(settings.url) ? settings.url + '&' + settings.data : settings.url + '?' + settings.data; +// +// } else { +// +// encodedString = ''; +// for(prop in settings.data) { +// +// encodedString += (prop + '=' + encodeURIComponent(settings.data[prop]) + '&'); +// +// } +// +// } +// +// if (settings.withCredentials) { +// +// XMLHTTP.withCredentials = true; +// +// } +// +// /** +// * Value returned in beforeSend funtion will be passed as context to the other response callbacks +// * If beforeSend returns false, AJAX will be blocked +// */ +// let responseContext, +// beforeSendResult; +// +// if (typeof settings.beforeSend === 'function') { +// +// beforeSendResult = settings.beforeSend.call(); +// +// if (beforeSendResult === false) { +// +// return; +// +// } +// +// } +// +// XMLHTTP.open( settings.type, settings.url, settings.async ); +// +// /** +// * If we send FormData, we need no content-type header +// */ +// isFormData = isFormData_(settings.data); +// +// if (!isFormData) { +// +// if (settings.type !== 'POST') { +// +// XMLHTTP.setRequestHeader('Content-type', settings['content-type']); +// +// } else { +// +// XMLHTTP.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); +// +// } +// +// } +// +// XMLHTTP.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); +// +// responseContext = beforeSendResult || XMLHTTP; +// +// if (typeof settings.progress === 'function') { +// +// XMLHTTP.upload.onprogress = settings.progress.bind(responseContext); +// +// } +// +// XMLHTTP.onreadystatechange = function () { +// +// if (XMLHTTP.readyState === 4) { +// +// if (XMLHTTP.status === 200) { +// +// if (typeof settings.success === 'function') { +// +// settings.success.call(responseContext, XMLHTTP.responseText); +// +// } +// +// } else { +// +// if (typeof settings.error === 'function') { +// +// settings.error.call(responseContext, XMLHTTP.responseText, XMLHTTP.status); +// +// } +// +// } +// +// } +// +// }; +// +// if (isFormData) { +// +// // Sending FormData +// XMLHTTP.send(settings.data); +// +// } else { +// +// // POST requests +// XMLHTTP.send(encodedString); +// +// } +// +// return XMLHTTP; +// +// }; +// +// /** +// * Appends script to head of document +// * @return Promise +// */ +// core.importScript = function (scriptPath, instanceName) { +// +// return new Promise(function (resolve, reject) { +// +// let script; +// +// /** Script is already loaded */ +// if ( !instanceName ) { +// +// reject('Instance name is missed'); +// +// } else if ( document.getElementById(editor.scriptPrefix + instanceName) ) { +// +// resolve(scriptPath); +// +// } +// +// script = document.createElement('SCRIPT'); +// script.async = true; +// script.defer = true; +// script.id = editor.scriptPrefix + instanceName; +// +// script.onload = function () { +// +// resolve(scriptPath); +// +// }; +// +// script.onerror = function () { +// +// reject(scriptPath); +// +// }; +// +// script.src = scriptPath; +// document.head.appendChild(script); +// +// }); +// +// }; +// +// /** +// * Function for checking is it FormData object to send. +// * @param {Object} object to check +// * @return boolean +// */ +// var isFormData_ = function (object) { +// +// return object instanceof FormData; +// +// }; +// +// /** +// * Check block +// * @param target +// * @description Checks target is it native input +// */ +// core.isNativeInput = function (target) { +// +// var nativeInputAreas = ['INPUT', 'TEXTAREA']; +// +// return nativeInputAreas.indexOf(target.tagName) != -1; +// +// }; +// +// /** +// * Check if block is empty +// * We should check block textContent, child native inputs and some exceptions like IMG and IFRAME +// * +// * @param block +// * @returns {boolean} +// */ +// core.isBlockEmpty = function (block) { +// +// const EXCEPTION_TAGS = ['IMG', 'IFRAME']; +// +// var nativeInputs = block.querySelectorAll('textarea, input'), +// nativeInputsAreEmpty = true, +// textContentIsEmpty = !block.textContent.trim(); +// +// Array.prototype.forEach.call(nativeInputs, function (input) { +// +// if (input.type == 'textarea' || input.type == 'text') { +// +// nativeInputsAreEmpty = nativeInputsAreEmpty && !input.value.trim(); +// +// } +// +// }); +// +// return textContentIsEmpty && nativeInputsAreEmpty && !EXCEPTION_TAGS.includes(block.tagName); +// +// }; +// +// +// return core; +// +// })({}); diff --git a/modules/destroyer.js b/src/modules/destroyer.js similarity index 100% rename from modules/destroyer.js rename to src/modules/destroyer.js diff --git a/modules/draw.js b/src/modules/draw.js similarity index 100% rename from modules/draw.js rename to src/modules/draw.js diff --git a/modules/listeners.js b/src/modules/listeners.js similarity index 100% rename from modules/listeners.js rename to src/modules/listeners.js diff --git a/modules/notifications.js b/src/modules/notifications.js similarity index 100% rename from modules/notifications.js rename to src/modules/notifications.js diff --git a/modules/parser.js b/src/modules/parser.js similarity index 100% rename from modules/parser.js rename to src/modules/parser.js diff --git a/modules/paste.js b/src/modules/paste.js similarity index 100% rename from modules/paste.js rename to src/modules/paste.js diff --git a/modules/renderer.js b/src/modules/renderer.js similarity index 100% rename from modules/renderer.js rename to src/modules/renderer.js diff --git a/modules/sanitizer.js b/src/modules/sanitizer.js similarity index 100% rename from modules/sanitizer.js rename to src/modules/sanitizer.js diff --git a/modules/saver.js b/src/modules/saver.js similarity index 100% rename from modules/saver.js rename to src/modules/saver.js diff --git a/modules/toolbar/inline.js b/src/modules/toolbar/inline.js similarity index 100% rename from modules/toolbar/inline.js rename to src/modules/toolbar/inline.js diff --git a/modules/toolbar/settings.js b/src/modules/toolbar/settings.js similarity index 100% rename from modules/toolbar/settings.js rename to src/modules/toolbar/settings.js diff --git a/modules/toolbar/toolbar.js b/src/modules/toolbar/toolbar.js similarity index 100% rename from modules/toolbar/toolbar.js rename to src/modules/toolbar/toolbar.js diff --git a/modules/toolbar/toolbox.js b/src/modules/toolbar/toolbox.js similarity index 100% rename from modules/toolbar/toolbox.js rename to src/modules/toolbar/toolbox.js diff --git a/modules/tools.js b/src/modules/tools.js similarity index 100% rename from modules/tools.js rename to src/modules/tools.js diff --git a/modules/transport.js b/src/modules/transport.js similarity index 100% rename from modules/transport.js rename to src/modules/transport.js diff --git a/modules/ui.js b/src/modules/ui.js similarity index 100% rename from modules/ui.js rename to src/modules/ui.js