diff --git a/.eslintrc b/.eslintrc index c79a0e97..badf3fb8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -27,7 +27,10 @@ "objectsInArrays": true, "arraysInArrays": true }], - "quotes": [2, "single", "avoid-escape"], + "quotes": [2, "single", { + "avoidEscape": true, + "allowTemplateLiterals": true + }], "eqeqeq": 0, "brace-style": [2, "1tbs"], "comma-spacing": [2, { @@ -75,7 +78,9 @@ "RegExp": true, "Module": true, "Node": true, + "Element": true, "Proxy": true, + "Symbol": true, "$": true, "_": true } diff --git a/build/codex-editor.js b/build/codex-editor.js index 148e06f4..f209b214 100644 --- a/build/codex-editor.js +++ b/build/codex-editor.js @@ -61,7 +61,7 @@ var CodexEditor = /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 3); +/******/ return __webpack_require__(__webpack_require__.s = 4); /******/ }) /************************************************************************/ /******/ ([ @@ -72,7 +72,7 @@ var CodexEditor = Object.defineProperty(exports, "__esModule", { - value: true + value: true }); 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; }; }(); @@ -82,7 +82,7 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons /** * @abstract * @class Module - * @classdesc All modules inherites from this class. + * @classdesc All modules inherits from this class. * * @typedef {Module} Module * @property {Object} config - Editor user settings @@ -90,44 +90,51 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons */ var Module = function () { - /** - * @constructor - * - * @param {EditorConfig} config - */ - function Module() { - var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - config = _ref.config; + /** + * @constructor + * + * @param {EditorConfig} config + */ + function Module() { + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + config = _ref.config; - _classCallCheck(this, Module); + _classCallCheck(this, Module); - if (new.target === Module) { + if (new.target === Module) { - throw new TypeError('Constructors for abstract class Module are not allowed.'); - } - - this.config = config; - this.Editor = null; + throw new TypeError('Constructors for abstract class Module are not allowed.'); } /** - * Editor modules setter - * - * @param Editor - * @param Editor.modules {@link CodexEditor#moduleInstances} - * @param Editor.config {@link CodexEditor#configuration} + * @type {EditorConfig} */ + this.config = config; + + /** + * @type {EditorComponents} + */ + this.Editor = null; + } + + /** + * Editor modules setter + * + * @param Editor + * @param Editor.modules {@link CodexEditor#moduleInstances} + * @param Editor.config {@link CodexEditor#configuration} + */ - _createClass(Module, [{ - key: 'state', - set: function set(Editor) { + _createClass(Module, [{ + key: 'state', + set: function set(Editor) { - this.Editor = Editor; - } - }]); + this.Editor = Editor; + } + }]); - return Module; + return Module; }(); Module.displayName = 'Module'; @@ -141,143 +148,6 @@ module.exports = exports['default']; "use strict"; -Object.defineProperty(exports, "__esModule", { - value: true -}); - -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 Util - */ -var Util = function () { - function Util() { - _classCallCheck(this, Util); - } - - _createClass(Util, null, [{ - key: "sequence", - - - /** - * @typedef {Object} ChainData - * @property {Object} data - data that will be passed to the success or fallback - * @property {Function} function - function's that must be called asynchronically - */ - - /** - * Fires a promise sequence asyncronically - * - * @param {Object[]} chains - list or ChainData's - * @param {Function} success - success callback - * @param {Function} fallback - callback that fires in case of errors - * - * @return {Promise} - */ - value: function sequence(chains) { - var success = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {}; - var fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {}; - - - return new Promise(function (resolve) { - - /** - * 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 - */ - chains.reduce(function (previousValue, currentValue, iteration) { - - return previousValue.then(function () { - return waitNextBlock(currentValue, success, fallback); - }).then(function () { - - // finished - if (iteration === chains.length - 1) { - - resolve(); - } - }); - }, Promise.resolve()); - }); - - /** - * Decorator - * - * @param {ChainData} chainData - * - * @param {Function} successCallback - * @param {Function} fallbackCallback - * - * @return {Promise} - */ - function waitNextBlock(chainData, successCallback, fallbackCallback) { - - return new Promise(function (resolve) { - - chainData.function().then(function () { - - successCallback(chainData.data); - }).then(resolve).catch(function () { - - fallbackCallback(chainData.data); - - // anyway, go ahead even it falls - resolve(); - }); - }); - } - } - - /** - * Make array from array-like collection - * - * @param {*} collection - * - * @return {Array} - */ - - }, { - key: "array", - value: function array(collection) { - - return Array.prototype.slice.call(collection); - } - - /** - * Checks if object is empty - * - * @param {Object} object - * @return {boolean} - */ - - }, { - key: "isEmpty", - value: function isEmpty(object) { - - return Object.keys(object).length === 0 && object.constructor === Object; - } - }]); - - return Util; -}(); - -Util.displayName = "Util"; -exports.default = Util; -; -module.exports = exports["default"]; - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - Object.defineProperty(exports, "__esModule", { value: true }); @@ -405,8 +275,8 @@ var Dom = function () { */ }, { - key: 'isNode', - value: function isNode(node) { + key: 'isElement', + value: function isElement(node) { return node && (typeof node === 'undefined' ? 'undefined' : _typeof(node)) === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE; } @@ -420,10 +290,344 @@ exports.default = Dom; ; module.exports = exports['default']; +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +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 Util + */ +var Util = function () { + function Util() { + _classCallCheck(this, Util); + } + + _createClass(Util, null, [{ + key: 'log', + + + /** + * Custom logger + * + * @param {string} msg - message + * @param {string} type - logging type 'log'|'warn'|'error'|'info' + * @param {*} args - argument to log with a message + */ + value: function log(msg, type, args) { + + type = type || 'log'; + + if (!args) { + + args = msg || 'undefined'; + msg = '[codex-editor]: %o'; + } else { + + msg = '[codex-editor]: ' + msg; + } + + try { + + if ('console' in window && window.console[type]) { + + if (args) window.console[type](msg, args);else window.console[type](msg); + } + } catch (e) { + // do nothing + } + } + + /** + * @typedef {Object} ChainData + * @property {Object} data - data that will be passed to the success or fallback + * @property {Function} function - function's that must be called asynchronically + */ + + /** + * Fires a promise sequence asyncronically + * + * @param {Object[]} chains - list or ChainData's + * @param {Function} success - success callback + * @param {Function} fallback - callback that fires in case of errors + * + * @return {Promise} + */ + + }, { + key: 'sequence', + value: function sequence(chains) { + var success = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {}; + var fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {}; + + + return new Promise(function (resolve) { + + /** + * 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 + */ + chains.reduce(function (previousValue, currentValue, iteration) { + + return previousValue.then(function () { + return waitNextBlock(currentValue, success, fallback); + }).then(function () { + + // finished + if (iteration === chains.length - 1) { + + resolve(); + } + }); + }, Promise.resolve()); + }); + + /** + * Decorator + * + * @param {ChainData} chainData + * + * @param {Function} successCallback + * @param {Function} fallbackCallback + * + * @return {Promise} + */ + function waitNextBlock(chainData, successCallback, fallbackCallback) { + + return new Promise(function (resolve) { + + chainData.function().then(function () { + + successCallback(chainData.data); + }).then(resolve).catch(function () { + + fallbackCallback(chainData.data); + + // anyway, go ahead even it falls + resolve(); + }); + }); + } + } + + /** + * Make array from array-like collection + * + * @param {*} collection + * + * @return {Array} + */ + + }, { + key: 'array', + value: function array(collection) { + + return Array.prototype.slice.call(collection); + } + + /** + * Checks if object is empty + * + * @param {Object} object + * @return {boolean} + */ + + }, { + key: 'isEmpty', + value: function isEmpty(object) { + + return Object.keys(object).length === 0 && object.constructor === Object; + } + }]); + + return Util; +}(); + +Util.displayName = 'Util'; +exports.default = Util; +; +module.exports = exports['default']; + /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { +"use strict"; +/* WEBPACK VAR INJECTION */(function($) { + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +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"); } } + +/** + * + * @class Block + * @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool + * + * @property {Tool} tool — current block tool (Paragraph, for example) + * @property {Object} CSS — block`s css classes + * + */ + +var Block = function () { + + /** + * @constructor + * + * @param {Object} tool — current block plugin`s instance + */ + function Block(tool) { + _classCallCheck(this, Block); + + this.tool = tool; + + this._html = this.compose(); + } + + /** + * CSS classes for the Block + * @return {{wrapper: string, content: string}} + */ + + + _createClass(Block, [{ + key: 'compose', + + + /** + * Make default block wrappers and put tool`s content there + * + * @returns {HTMLDivElement} + * @private + */ + value: function compose() { + + var wrapper = $.make('div', Block.CSS.wrapper), + content = $.make('div', Block.CSS.content); + + content.appendChild(this.tool.html); + wrapper.appendChild(content); + + return wrapper; + } + + /** + * Get block`s HTML + * + * @returns {HTMLDivElement} + */ + + }, { + key: 'html', + get: function get() { + + return this._html; + } + + /** + * Check block for emptiness + * + * @return {Boolean} + */ + + }, { + key: 'isEmpty', + get: function get() { + + /** + * Allow Tool to represent decorative contentless blocks: for example "* * *"-tool + * That Tools are not empty + */ + if (this.tool.contentless) { + + return false; + } + + var emptyText = this._html.textContent.trim().length === 0, + emptyMedia = !this.hasMedia; + + return emptyText && emptyMedia; + } + + /** + * Check if block has a media content such as images, iframes and other + * @return {Boolean} + */ + + }, { + key: 'hasMedia', + get: function get() { + + /** + * This tags represents media-content + * @type {string[]} + */ + var mediaTags = ['img', 'iframe', 'video', 'audio', 'source', 'input', 'textarea', 'twitterwidget']; + + return !!this._html.querySelector(mediaTags.join(',')); + } + + /** + * Set selected state + * @param {Boolean} state - 'true' to select, 'false' to remove selection + */ + + }, { + key: 'selected', + set: function set(state) { + + /** + * We don't need to mark Block as Selected when it is not empty + */ + if (state === true && !this.isEmpty) { + + this._html.classList.add(Block.CSS.selected); + } else { + + this._html.classList.remove(Block.CSS.selected); + } + } + }], [{ + key: 'CSS', + get: function get() { + + return { + wrapper: 'ce-block', + content: 'ce-block__content', + selected: 'ce-block--selected' + }; + } + }]); + + return Block; +}(); + +Block.displayName = 'Block'; +exports.default = Block; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + "use strict"; /** * Codex Editor @@ -472,26 +676,41 @@ module.exports = exports['default']; /** * @typedef {Object} EditorConfig - * @property {String} holderId - Element to append Editor - * @property {String} initialBlock - Tool name which will be initial - * @property {Object} tools - list of tools. The object value must be function (constructor) so that CodexEditor could make an instance - * @property {@link Tools#ToolsConfig} toolsConfig - tools configuration - * @property {Array} data - Blocks list in JSON-format + * @property {String} holderId - Element to append Editor + * @property {Array} data - Blocks list in JSON-format + * @property {Object} tools - Map for used Tools in format { name : Class, ... } + * @property {String} initialBlock - This Tool will be added by default + * @property {String} placeholder - First Block placeholder + * @property {Object} sanitizer - @todo fill desc + * @property {Boolean} hideToolbar - @todo fill desc + * @property {Object} toolsConfig - tools configuration {@link Tools#ToolsConfig} + */ + +/** + * Dynamically imported utils + * + * @typedef {Dom} $ - {@link components/dom.js} + * @typedef {Util} _ - {@link components/utils.js} */ /** - * Require Editor modules places in components/modules dir + * Apply polyfills */ -// eslint-disable-next-line 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; }; }(); +__webpack_require__(5); + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -var modules = ["blockManager.js","events.js","renderer.js","sanitizer.js","toolbar.js","tools.js","ui.js"].map(function (module) { - return __webpack_require__(4)("./" + module); +/** + * Require Editor modules places in components/modules dir + */ +// eslint-disable-next-line +var modules = ["blockManager.js","caret.js","events.js","renderer.js","toolbar.js","toolbox.js","tools.js","ui.js"].map(function (module) { + return __webpack_require__(6)("./" + module); }); /** @@ -529,11 +748,19 @@ module.exports = function () { /** * Configuration object + * @type {EditorConfig} */ this.config = {}; /** - * Editor Components + * @typedef {Object} EditorComponents + * @property {BlockManager} BlockManager + * @property {Tools} Tools + * @property {Events} Events + * @property {UI} UI + * @property {Toolbar} Toolbar + * @property {Toolbox} Toolbox + * @property {Renderer} Renderer */ this.moduleInstances = {}; @@ -549,13 +776,13 @@ module.exports = function () { console.log('CodeX Editor is ready'); }).catch(function (error) { - console.log('CodeX Editor does not ready beecause of %o', error); + console.log('CodeX Editor does not ready because of %o', error); }); } /** * Setting for configuration - * @param {Object} config + * @param {EditorConfig} config */ @@ -601,7 +828,6 @@ module.exports = function () { * To prevent this, we use 'babel-plugin-class-display-name' plugin * @see https://www.npmjs.com/package/babel-plugin-class-display-name */ - _this2.moduleInstances[Module.displayName] = new Module({ config: _this2.configuration }); @@ -671,7 +897,7 @@ module.exports = function () { return module.prepare(); }; - return Promise.resolve().then(prepareDecorator(this.moduleInstances.UI)).then(prepareDecorator(this.moduleInstances.Tools)).then(function () { + return Promise.resolve().then(prepareDecorator(this.moduleInstances.Tools)).then(prepareDecorator(this.moduleInstances.UI)).then(function () { if (_this3.config.data && _this3.config.data.items) { @@ -684,9 +910,7 @@ module.exports = function () { } }, { key: 'configuration', - set: function set() { - var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - + set: function set(config) { this.config.holderId = config.holderId; this.config.placeholder = config.placeholder || 'write your story...'; @@ -700,11 +924,24 @@ module.exports = function () { this.config.tools = config.tools || {}; this.config.toolsConfig = config.toolsConfig || {}; this.config.data = config.data || []; + + /** + * If initial Block's Tool was not passed, use the first Tool in config.tools + */ + if (!config.initialBlock) { + + for (this.config.initialBlock in this.config.tools) { + break; + } + } else { + + this.config.initialBlock = config.initialBlock; + } } /** * Returns private property - * @returns {{}|*} + * @returns {EditorConfig} */ , get: function get() { @@ -750,11 +987,11 @@ module.exports = function () { // * holds initial settings // */ // editor.settings = { -// tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'], +// tools : ['text', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'], // holderId : 'codex-editor', // // // Type of block showing on empty editor -// initialBlockPlugin: 'paragraph' +// initialBlockPlugin: 'text' // }; // // /** @@ -827,17 +1064,45 @@ module.exports = function () { // })({}); /***/ }), -/* 4 */ +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Element.closest() + * + * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest + */ +if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; + +if (!Element.prototype.closest) Element.prototype.closest = function (s) { + + var el = this; + + if (!document.documentElement.contains(el)) return null; + do { + + if (el.matches(s)) return el; + el = el.parentElement || el.parentNode; + } while (el !== null); + return null; +}; + +/***/ }), +/* 6 */ /***/ (function(module, exports, __webpack_require__) { var map = { - "./blockManager.js": 5, - "./events.js": 7, - "./renderer.js": 8, - "./sanitizer.js": 9, + "./blockManager.js": 7, + "./caret.js": 8, + "./events.js": 9, + "./renderer.js": 10, "./toolbar.js": 11, - "./tools.js": 12, - "./ui.js": 13 + "./toolbox.js": 12, + "./tools.js": 13, + "./ui.js": 14 }; function webpackContext(req) { return __webpack_require__(webpackContextResolve(req)); @@ -853,14 +1118,14 @@ webpackContext.keys = function webpackContextKeys() { }; webpackContext.resolve = webpackContextResolve; module.exports = webpackContext; -webpackContext.id = 4; +webpackContext.id = 6; /***/ }), -/* 5 */ +/* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* WEBPACK VAR INJECTION */(function(Module, _) { +/* WEBPACK VAR INJECTION */(function(Module, $, _) { Object.defineProperty(exports, "__esModule", { value: true @@ -868,7 +1133,7 @@ Object.defineProperty(exports, "__esModule", { 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; }; }(); -var _block = __webpack_require__(6); +var _block = __webpack_require__(3); var _block2 = _interopRequireDefault(_block); @@ -885,6 +1150,11 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" * @module BlockManager */ +/** + * @typedef {BlockManager} BlockManager + * @property {Number} currentBlockIndex - Index of current working block + * @property {Proxy} _blocks - Proxy for Blocks instance {@link Blocks} + */ var BlockManager = function (_Module) { _inherits(BlockManager, _Module); @@ -892,7 +1162,9 @@ var BlockManager = function (_Module) { * @constructor * @param {EditorConfig} config */ - function BlockManager(config) { + function BlockManager(_ref) { + var config = _ref.config; + _classCallCheck(this, BlockManager); /** @@ -901,7 +1173,7 @@ var BlockManager = function (_Module) { * @type {Proxy} * @private */ - var _this = _possibleConstructorReturn(this, (BlockManager.__proto__ || Object.getPrototypeOf(BlockManager)).call(this, config)); + var _this = _possibleConstructorReturn(this, (BlockManager.__proto__ || Object.getPrototypeOf(BlockManager)).call(this, { config: config })); _this._blocks = null; @@ -965,12 +1237,18 @@ var BlockManager = function (_Module) { }, { key: 'insert', - value: function insert(toolName, data) { + value: function insert(toolName) { + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var toolInstance = this.Editor.Tools.construct(toolName, data), block = new _block2.default(toolInstance); this._blocks[++this.currentBlockIndex] = block; + + /** + * @todo fire Tool's appendCallback + */ } /** @@ -982,12 +1260,18 @@ var BlockManager = function (_Module) { }, { key: 'replace', - value: function replace(toolName, data) { + value: function replace(toolName) { + var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var toolInstance = this.Editor.Tools.construct(toolName, data), block = new _block2.default(toolInstance); this._blocks.insert(this.currentBlockIndex, block, true); + + /** + * @todo fire Tool's appendCallback + */ } /** @@ -1018,6 +1302,37 @@ var BlockManager = function (_Module) { * @return {Block} */ + }, { + key: 'setCurrentBlockByChildNode', + + + /** + * 1) Find first-level Block from passed child Node + * 2) Mark it as current + * + * @param {Element|Text} childNode - look ahead from this node. + * @throws Error - when passed Node is not included at the Block + */ + value: function setCurrentBlockByChildNode(childNode) { + + /** + * If node is Text TextNode + */ + if (!$.isElement(childNode)) { + + childNode = childNode.parentNode; + } + + var parentFirstLevelBlock = childNode.closest('.' + _block2.default.CSS.wrapper); + + if (parentFirstLevelBlock) { + + this.currentNode = parentFirstLevelBlock; + } else { + + throw new Error('Can not find a Block from this child Node'); + } + } }, { key: 'currentBlock', get: function get() { @@ -1050,7 +1365,24 @@ var BlockManager = function (_Module) { var nodes = this._blocks.nodes; + /** + * Update current Block's index + * @type {number} + */ this.currentBlockIndex = nodes.indexOf(element); + + /** + * Remove previous selected Block's state + */ + this._blocks.array.forEach(function (block) { + return block.selected = false; + }); + + /** + * Mark current Block as selected + * @type {boolean} + */ + this.currentBlock.selected = true; } /** @@ -1303,14 +1635,14 @@ var Blocks = function () { Blocks.displayName = 'Blocks'; module.exports = exports['default']; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1))) +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1), __webpack_require__(2))) /***/ }), -/* 6 */ +/* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* WEBPACK VAR INJECTION */(function($) { +/* WEBPACK VAR INJECTION */(function(Module) { Object.defineProperty(exports, "__esModule", { value: true @@ -1320,81 +1652,132 @@ var _createClass = function () { function defineProperties(target, props) { for function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -/** - * - * @class Block - * @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool - * - * @property {Tool} tool — current block tool (Paragraph, for example) - * @property {Object} CSS — block`s css classes - * - */ +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } -var Block = function () { +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/** + * @class Caret + * @classdesc Contains methods for working Caret + * + * @typedef {Caret} Caret + */ +var Caret = function (_Module) { + _inherits(Caret, _Module); /** * @constructor - * - * @param {Object} tool — current block plugin`s instance */ - function Block(tool) { - _classCallCheck(this, Block); + function Caret(_ref) { + var config = _ref.config; - this.tool = tool; + _classCallCheck(this, Caret); - this.CSS = { - wrapper: 'ce-block', - content: 'ce-block__content' - }; - - this._html = this.compose(); + return _possibleConstructorReturn(this, (Caret.__proto__ || Object.getPrototypeOf(Caret)).call(this, { config: config })); } /** - * Make default block wrappers and put tool`s content there + * Set Caret to the last Block * - * @returns {HTMLDivElement} - * @private + * If last block is not empty, append another empty block */ - _createClass(Block, [{ - key: 'compose', - value: function compose() { + _createClass(Caret, [{ + key: 'setToTheLastBlock', + value: function setToTheLastBlock() { - var wrapper = $.make('div', this.CSS.wrapper), - content = $.make('div', this.CSS.content); + var blocks = this.Editor.BlockManager.blocks, + lastBlock = void 0; - content.appendChild(this.tool.html); - wrapper.appendChild(content); + if (blocks.length) { - return wrapper; + lastBlock = blocks[blocks.length - 1]; + } + + /** + * If last block is empty and it is an initialBlock, set to that. + * Otherwise, append new empty block and set to that + */ + if (lastBlock.isEmpty) { + + this.set(lastBlock.html); + } else { + + this.Editor.BlockManager.insert(this.config.initialBlock); + } + + /** + // * 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); + // + // } + // + // } } /** - * Get block`s HTML - * - * @returns {HTMLDivElement} + * Set caret to the passed Node + * @param {Element} node - content-editable Element */ }, { - key: 'html', - get: function get() { + key: 'set', + value: function set(node) { - return this._html; + /** + * @todo add working with Selection + * tmp: work with textContent + */ + + node.textContent += '|'; } }]); - return Block; -}(); + return Caret; +}(Module); -Block.displayName = 'Block'; -exports.default = Block; +Caret.displayName = 'Caret'; +exports.default = Caret; module.exports = exports['default']; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) /***/ }), -/* 7 */ +/* 9 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -1430,10 +1813,12 @@ var Events = function (_Module) { /** * @constructor */ - function Events(config) { + function Events(_ref) { + var config = _ref.config; + _classCallCheck(this, Events); - var _this = _possibleConstructorReturn(this, (Events.__proto__ || Object.getPrototypeOf(Events)).call(this, config)); + var _this = _possibleConstructorReturn(this, (Events.__proto__ || Object.getPrototypeOf(Events)).call(this, { config: config })); _this.subscribers = {}; @@ -1498,7 +1883,7 @@ module.exports = exports["default"]; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) /***/ }), -/* 8 */ +/* 10 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -1531,10 +1916,12 @@ var Renderer = function (_Module) { * @constructor * @param {EditorConfig} config */ - function Renderer(config) { + function Renderer(_ref) { + var config = _ref.config; + _classCallCheck(this, Renderer); - return _possibleConstructorReturn(this, (Renderer.__proto__ || Object.getPrototypeOf(Renderer)).call(this, config)); + return _possibleConstructorReturn(this, (Renderer.__proto__ || Object.getPrototypeOf(Renderer)).call(this, { config: config })); } /** @@ -1819,373 +2206,7 @@ var Renderer = function (_Module) { Renderer.displayName = "Renderer"; exports.default = Renderer; module.exports = exports["default"]; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(Module, _) { - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -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"); } } - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/** - * CodeX Sanitizer - * - * @module Sanitizer - * Clears HTML from taint tags - * - * @version 2.0.0 - * - * @example - * Module can be used within two ways: - * 1) When you have an instance - * - this.Editor.Sanitizer.clean(yourTaintString); - * 2) As static method - * - CodexEditor.Sanitizer.clean(yourTaintString, yourCustomConfiguration); - * - * {@link SanitizerConfig} - */ - -/** - * @typedef {Object} SanitizerConfig - * @property {Object} tags - define tags restrictions - * - * @example - * - * tags : { - * p: true, - * a: { - * href: true, - * rel: "nofollow", - * target: "_blank" - * } - * } - */ -var Sanitizer = function (_Module) { - _inherits(Sanitizer, _Module); - - /** - * Initializes Sanitizer module - * Sets default configuration if custom not exists - * - * @property {SanitizerConfig} this.defaultConfig - * @property {HTMLJanitor} this._sanitizerInstance - Sanitizer library - * - * @param {SanitizerConfig} config - */ - function Sanitizer(config) { - _classCallCheck(this, Sanitizer); - - // default config - var _this = _possibleConstructorReturn(this, (Sanitizer.__proto__ || Object.getPrototypeOf(Sanitizer)).call(this, config)); - - _this.defaultConfig = null; - _this._sanitizerInstance = null; - - /** Custom configuration */ - _this.sanitizerConfig = config.settings ? config.settings.sanitizer : {}; - - /** HTML Janitor library */ - _this.sanitizerInstance = __webpack_require__(10); - - return _this; - } - - /** - * If developer uses editor's API, then he can customize sanitize restrictions. - * Or, sanitizing 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 Default configuration - * - * @uses https://www.npmjs.com/package/html-janitor - * - * @param {HTMLJanitor} library - sanitizer extension - */ - - - _createClass(Sanitizer, [{ - key: 'clean', - - - /** - * Cleans string from unwanted tags - * @param {String} taintString - HTML string - * - * @return {String} clean HTML - */ - value: function clean(taintString) { - - return this._sanitizerInstance.clean(taintString); - } - - /** - * Cleans string from unwanted tags - * @static - * - * Method allows to use default config - * - * @param {String} taintString - taint string - * @param {SanitizerConfig} customConfig - allowed tags - * - * @return {String} clean HTML - */ - - }, { - key: 'sanitizerInstance', - set: function set(library) { - - this._sanitizerInstance = new library(this.defaultConfig); - } - - /** - * Sets sanitizer configuration. Uses default config if user didn't pass the restriction - * @param {SanitizerConfig} config - */ - - }, { - key: 'sanitizerConfig', - set: function set(config) { - - if (_.isEmpty(config)) { - - this.defaultConfig = { - tags: { - p: {}, - a: { - href: true, - target: '_blank', - rel: 'nofollow' - } - } - }; - } else { - - this.defaultConfig = config; - } - } - }], [{ - key: 'clean', - value: function clean(taintString, customConfig) { - - var newInstance = Sanitizer(customConfig); - - return newInstance.clean(taintString); - } - }]); - - return Sanitizer; -}(Module); - -Sanitizer.displayName = 'Sanitizer'; -exports.default = Sanitizer; -module.exports = exports['default']; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1))) - -/***/ }), -/* 10 */ -/***/ (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; - -})); - +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(2))) /***/ }), /* 11 */ @@ -2263,10 +2284,12 @@ var Toolbar = function (_Module) { /** * @constructor */ - function Toolbar(config) { + function Toolbar(_ref) { + var config = _ref.config; + _classCallCheck(this, Toolbar); - var _this = _possibleConstructorReturn(this, (Toolbar.__proto__ || Object.getPrototypeOf(Toolbar)).call(this, config)); + var _this = _possibleConstructorReturn(this, (Toolbar.__proto__ || Object.getPrototypeOf(Toolbar)).call(this, { config: config })); _this.nodes = { wrapper: null, @@ -2275,7 +2298,6 @@ var Toolbar = function (_Module) { // Content Zone plusButton: null, - toolbox: null, // Actions Zone settingsToggler: null, @@ -2287,46 +2309,34 @@ var Toolbar = function (_Module) { defaultSettings: null }; - _this.CSS = { - toolbar: 'ce-toolbar', - content: 'ce-toolbar__content', - actions: 'ce-toolbar__actions', - - // Content Zone - toolbox: 'ce-toolbar__toolbox', - plusButton: 'ce-toolbar__plus', - - // Actions Zone - settingsToggler: 'ce-toolbar__settings-btn', - removeBlockButton: 'ce-toolbar__remove-btn', - - // Settings Panel - settings: 'ce-settings', - defaultSettings: 'ce-settings_default', - pluginSettings: 'ce-settings_plugin' - }; - return _this; } /** - * Makes toolbar + * CSS styles + * @return {Object} + * @constructor */ _createClass(Toolbar, [{ key: 'make', + + + /** + * Makes toolbar + */ value: function make() { var _this2 = this; - this.nodes.wrapper = $.make('div', this.CSS.toolbar); + this.nodes.wrapper = $.make('div', Toolbar.CSS.toolbar); /** * Make Content Zone and Actions Zone */ ['content', 'actions'].forEach(function (el) { - _this2.nodes[el] = $.make('div', _this2.CSS[el]); + _this2.nodes[el] = $.make('div', Toolbar.CSS[el]); $.append(_this2.nodes.wrapper, _this2.nodes[el]); }); @@ -2335,11 +2345,16 @@ var Toolbar = function (_Module) { * - Plus Button * - Toolbox */ - ['plusButton', 'toolbox'].forEach(function (el) { + this.nodes.plusButton = $.make('div', Toolbar.CSS.plusButton); + $.append(this.nodes.content, this.nodes.plusButton); + this.nodes.plusButton.addEventListener('click', function (event) { + return _this2.plusButtonClicked(event); + }, false); - _this2.nodes[el] = $.make('div', _this2.CSS[el]); - $.append(_this2.nodes.content, _this2.nodes[el]); - }); + /** + * Make a Toolbox + */ + this.Editor.Toolbox.make(); /** * Fill Actions Zone: @@ -2347,7 +2362,7 @@ var Toolbar = function (_Module) { * - Remove Block Button * - Settings Panel */ - this.nodes.settingsToggler = $.make('span', this.CSS.settingsToggler); + this.nodes.settingsToggler = $.make('span', Toolbar.CSS.settingsToggler); this.nodes.removeBlockButton = this.makeRemoveBlockButton(); $.append(this.nodes.actions, [this.nodes.settingsToggler, this.nodes.removeBlockButton]); @@ -2373,10 +2388,10 @@ var Toolbar = function (_Module) { key: 'makeBlockSettingsPanel', value: function makeBlockSettingsPanel() { - this.nodes.settings = $.make('div', this.CSS.settings); + this.nodes.settings = $.make('div', Toolbar.CSS.settings); - this.nodes.pluginSettings = $.make('div', this.CSS.pluginSettings); - this.nodes.defaultSettings = $.make('div', this.CSS.defaultSettings); + this.nodes.pluginSettings = $.make('div', Toolbar.CSS.pluginSettings); + this.nodes.defaultSettings = $.make('div', Toolbar.CSS.defaultSettings); $.append(this.nodes.settings, [this.nodes.pluginSettings, this.nodes.defaultSettings]); $.append(this.nodes.actions, this.nodes.settings); @@ -2395,7 +2410,122 @@ var Toolbar = function (_Module) { * @todo add confirmation panel and handlers * @see {@link settings#makeRemoveBlockButton} */ - return $.make('span', this.CSS.removeBlockButton); + return $.make('span', Toolbar.CSS.removeBlockButton); + } + + /** + * Move Toolbar to the Current Block + */ + + }, { + key: 'move', + value: function move() { + + /** Close Toolbox when we move toolbar */ + this.Editor.Toolbox.close(); + + var currentNode = this.Editor.BlockManager.currentNode; + + /** + * If no one Block selected as a Current + */ + if (!currentNode) { + + return; + } + + /** + * @todo Compute dynamically on prepare + * @type {number} + */ + var defaultToolbarHeight = 49; + var defaultOffset = 34; + + var newYCoordinate = currentNode.offsetTop - defaultToolbarHeight / 2 + defaultOffset; + + this.nodes.wrapper.style.transform = 'translate3D(0, ' + Math.floor(newYCoordinate) + 'px, 0)'; + + /** Close trash actions */ + // editor.toolbar.settings.hideRemoveActions(); + } + + /** + * Open Toolbar with Plus Button + */ + + }, { + key: 'open', + value: function open() { + + this.nodes.wrapper.classList.add(Toolbar.CSS.toolbarOpened); + } + + /** + * Close the Toolbar + */ + + }, { + key: 'close', + value: function close() { + + this.nodes.wrapper.classList.remove(Toolbar.CSS.toolbarOpened); + } + + /** + * Plus Button public methods + * @return {{hide: function(): void, show: function(): void}} + */ + + }, { + key: 'plusButtonClicked', + + + /** + * Handler for Plus Button + * @param {MouseEvent} event + */ + value: function plusButtonClicked(event) { + + this.Editor.Toolbox.toggle(); + } + }, { + key: 'plusButton', + get: function get() { + var _this3 = this; + + return { + hide: function hide() { + return _this3.nodes.plusButton.classList.add(Toolbar.CSS.plusButtonHidden); + }, + show: function show() { + return _this3.nodes.plusButton.classList.remove(Toolbar.CSS.plusButtonHidden); + } + }; + } + }], [{ + key: 'CSS', + get: function get() { + + return { + toolbar: 'ce-toolbar', + content: 'ce-toolbar__content', + actions: 'ce-toolbar__actions', + + toolbarOpened: 'ce-toolbar--opened', + + // Content Zone + plusButton: 'ce-toolbar__plus', + plusButtonHidden: 'ce-toolbar__plus--hidden', + + // Actions Zone + settingsToggler: 'ce-toolbar__settings-btn', + removeBlockButton: 'ce-toolbar__remove-btn', + + // Settings Panel + settings: 'ce-settings', + defaultSettings: 'ce-settings_default', + pluginSettings: 'ce-settings_plugin' + }; } }]); @@ -2405,12 +2535,277 @@ var Toolbar = function (_Module) { Toolbar.displayName = 'Toolbar'; exports.default = Toolbar; module.exports = exports['default']; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(2))) +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1))) /***/ }), /* 12 */ /***/ (function(module, exports, __webpack_require__) { +"use strict"; +/* WEBPACK VAR INJECTION */(function(Module, $, _) { + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +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"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/** + * @class Toolbox + * @classdesc Holder for Tools + * + * @typedef {Toolbox} Toolbox + * @property {Boolean} opened - opening state + * @property {Object} nodes - Toolbox nodes + * @property {Object} CSS - CSS class names + * + */ +var Toolbox = function (_Module) { + _inherits(Toolbox, _Module); + + /** + * @constructor + */ + function Toolbox(_ref) { + var config = _ref.config; + + _classCallCheck(this, Toolbox); + + var _this = _possibleConstructorReturn(this, (Toolbox.__proto__ || Object.getPrototypeOf(Toolbox)).call(this, { config: config })); + + _this.nodes = { + toolbox: null, + buttons: [] + }; + + /** + * Opening state + * @type {boolean} + */ + _this.opened = false; + + return _this; + } + + /** + * CSS styles + * @return {{toolbox: string, toolboxButton: string, toolboxOpened: string}} + */ + + + _createClass(Toolbox, [{ + key: 'make', + + + /** + * Makes the Toolbox + */ + value: function make() { + + this.nodes.toolbox = $.make('div', Toolbox.CSS.toolbox); + $.append(this.Editor.Toolbar.nodes.content, this.nodes.toolbox); + + this.addTools(); + } + + /** + * Iterates available tools and appends them to the Toolbox + */ + + }, { + key: 'addTools', + value: function addTools() { + + var tools = this.Editor.Tools.toolsAvailable; + + for (var toolName in tools) { + + this.addTool(toolName, tools[toolName]); + } + } + + /** + * Append Tool to the Toolbox + * + * @param {string} toolName - tool name + * @param {Tool} tool - tool class + */ + + }, { + key: 'addTool', + value: function addTool(toolName, tool) { + var _this2 = this; + + if (tool.displayInToolbox && !tool.iconClassName) { + + _.log('Toolbar icon class name is missed. Tool %o skipped', 'warn', toolName); + return; + } + + /** + * @todo Add checkup for the render method + */ + // if (typeof tool.render !== 'function') { + // + // _.log('render method missed. Tool %o skipped', 'warn', tool); + // return; + // + // } + + /** + * Skip tools that pass 'displayInToolbox=false' + */ + if (!tool.displayInToolbox) { + + return; + } + + var button = $.make('li', [Toolbox.CSS.toolboxButton, tool.iconClassName], { + title: toolName + }); + + /** + * Save tool's name in the button data-name + */ + button.dataset.name = toolName; + + $.append(this.nodes.toolbox, button); + + this.nodes.toolbox.appendChild(button); + this.nodes.buttons.push(button); + + /** + * @todo add event with module Listeners + */ + // this.Editor.Listeners.add(); + button.addEventListener('click', function (event) { + + _this2.buttonClicked(event); + }, false); + } + + /** + * Toolbox button click listener + * 1) if block is empty -> replace + * 2) if block is not empty -> add new block below + * + * @param {MouseEvent} event + */ + + }, { + key: 'buttonClicked', + value: function buttonClicked(event) { + + var toolButton = event.target, + toolName = toolButton.dataset.name, + tool = this.Editor.Tools.toolClasses[toolName]; + + /** + * @type {Block} + */ + var currentBlock = this.Editor.BlockManager.currentBlock; + + /** + * We do replace if: + * - block is empty + * - block is not irreplaceable + * @type {Array} + */ + if (!tool.irreplaceable && currentBlock.isEmpty) { + + this.Editor.BlockManager.replace(toolName); + } else { + + this.Editor.BlockManager.insert(toolName); + } + + /** + * @todo set caret to the new block + */ + + // window.setTimeout(function () { + + /** Set caret to current block */ + // editor.caret.setToBlock(currentInputIndex); + + // }, 10); + + /** + * Move toolbar when node is changed + */ + this.Editor.Toolbar.move(); + } + + /** + * Open Toolbox with Tools + */ + + }, { + key: 'open', + value: function open() { + + this.nodes.toolbox.classList.add(Toolbox.CSS.toolboxOpened); + this.opened = true; + } + + /** + * Close Toolbox + */ + + }, { + key: 'close', + value: function close() { + + this.nodes.toolbox.classList.remove(Toolbox.CSS.toolboxOpened); + this.opened = false; + } + + /** + * Close Toolbox + */ + + }, { + key: 'toggle', + value: function toggle() { + + if (!this.opened) { + + this.open(); + } else { + + this.close(); + } + } + }], [{ + key: 'CSS', + get: function get() { + + return { + toolbox: 'ce-toolbox', + toolboxButton: 'ce-toolbox__button', + toolboxOpened: 'ce-toolbox--opened' + }; + } + }]); + + return Toolbox; +}(Module); + +Toolbox.displayName = 'Toolbox'; +exports.default = Toolbox; +module.exports = exports['default']; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1), __webpack_require__(2))) + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + "use strict"; /* WEBPACK VAR INJECTION */(function(Module, _) { @@ -2433,10 +2828,9 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" */ /** - * Load user defined tools - * Tools must contain the following important objects: + * Each Tool must contain the following important objects: * - * @typedef {Object} ToolsConfig + * @typedef {Object} ToolConfig {@link docs/tools.md} * @property {String} iconClassname - this a icon in toolbar * @property {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE * @property {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE @@ -2447,15 +2841,28 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" */ /** - * @typedef {Tool} Tool - * @property {String} name - name of this module - * @property {Object[]} toolInstances - list of tool instances - * @property {Tools[]} available - available Tools - * @property {Tools[]} unavailable - unavailable Tools + * @typedef {Function} Tool {@link docs/tools.md} + * @property {Boolean} displayInToolbox - By default, tools won't be added in the Toolbox. Pass true to add. + * @property {String} iconClassName - CSS class name for the Toolbox button + * @property {Boolean} irreplaceable - Toolbox behaviour: replace or add new block below + * @property render + * @property save + * @property settings + * @property validate + * + * @todo update according to current API + * @todo describe Tool in the {@link docs/tools.md} + */ + +/** + * Class properties: + * + * @typedef {Tools} Tools + * @property {Tools[]} toolsAvailable - available Tools + * @property {Tools[]} toolsUnavailable - unavailable Tools * @property {Object} toolsClasses - all classes * @property {EditorConfig} config - Editor config */ - var Tools = function (_Module) { _inherits(Tools, _Module); @@ -2485,36 +2892,58 @@ var Tools = function (_Module) { } /** - * If config wasn't passed by user - * @return {ToolsConfig} + * Static getter for default Tool config fields + * + * @usage Tools.defaultConfig.displayInToolbox + * @return {ToolConfig} */ - }, { + }], [{ key: 'defaultConfig', get: function get() { return { - iconClassName: 'default-icon', + iconClassName: '', displayInToolbox: false, - enableLineBreaks: false + enableLineBreaks: false, + irreplaceable: false }; } /** * @constructor * - * @param {ToolsConfig} config + * @param {EditorConfig} config */ }]); - function Tools(config) { + function Tools(_ref) { + var config = _ref.config; + _classCallCheck(this, Tools); - var _this = _possibleConstructorReturn(this, (Tools.__proto__ || Object.getPrototypeOf(Tools)).call(this, config)); + /** + * Map {name: Class, ...} where: + * name — block type name in JSON. Got from EditorConfig.tools keys + * @type {Object} + */ + var _this = _possibleConstructorReturn(this, (Tools.__proto__ || Object.getPrototypeOf(Tools)).call(this, { config: config })); _this.toolClasses = {}; + + /** + * Available tools list + * {name: Class, ...} + * @type {Object} + */ _this.toolsAvailable = {}; + + /** + * Tools that rejected a prepare method + * {name: Class, ... } + * @type {Object} + */ _this.toolsUnavailable = {}; return _this; @@ -2522,7 +2951,7 @@ var Tools = function (_Module) { /** * Creates instances via passed or default configuration - * @return {boolean} + * @return {Promise} */ @@ -2568,7 +2997,7 @@ var Tools = function (_Module) { /** * Binds prepare function of plugins with user or default config - * @return {Array} list of functions that needs to be fired sequently + * @return {Array} list of functions that needs to be fired sequentially */ }, { @@ -2589,6 +3018,12 @@ var Tools = function (_Module) { toolName: toolName } }); + } else { + + /** + * If Tool hasn't a prepare method, mark it as available + */ + this.toolsAvailable[toolName] = toolClass; } } @@ -2617,18 +3052,6 @@ var Tools = function (_Module) { this.toolsUnavailable[data.toolName] = this.toolClasses[data.toolName]; } - /** - * Returns all tools - * @return {Array} - */ - - }, { - key: 'getTools', - value: function getTools() { - - return this.toolInstances; - } - /** * Return tool`a instance * @@ -2655,6 +3078,19 @@ var Tools = function (_Module) { return instance; } + + /** + * Check if passed Tool is an instance of Initial Block Tool + * @param {Tool} tool - Tool to check + * @return {Boolean} + */ + + }, { + key: 'isInitial', + value: function isInitial(tool) { + + return tool instanceof this.available[this.config.initialBlock]; + } }]); return Tools; @@ -2663,10 +3099,10 @@ var Tools = function (_Module) { Tools.displayName = 'Tools'; exports.default = Tools; module.exports = exports['default']; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1))) +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(2))) /***/ }), -/* 13 */ +/* 14 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -2678,17 +3114,21 @@ Object.defineProperty(exports, "__esModule", { 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; }; }(); +var _block = __webpack_require__(3); + +var _block2 = _interopRequireDefault(_block); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -/** - * Module UI - * - * @type {UI} - */ +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /** + * Module UI + * + * @type {UI} + */ // let className = { /** @@ -2717,11 +3157,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" // SETTINGS_ITEM : 'ce-settings__item' // }; -var CSS = { - editorWrapper: 'codex-editor', - editorZone: 'ce-redactor' -}; - /** * @class * @@ -2740,7 +3175,6 @@ var CSS = { * @property {Element} nodes.wrapper - * @property {Element} nodes.redactor - */ - var UI = function (_Module) { _inherits(UI, _Module); @@ -2749,10 +3183,12 @@ var UI = function (_Module) { * * @param {EditorConfig} config */ - function UI(config) { + function UI(_ref) { + var config = _ref.config; + _classCallCheck(this, UI); - var _this = _possibleConstructorReturn(this, (UI.__proto__ || Object.getPrototypeOf(UI)).call(this, config)); + var _this = _possibleConstructorReturn(this, (UI.__proto__ || Object.getPrototypeOf(UI)).call(this, { config: config })); _this.nodes = { holder: null, @@ -2775,43 +3211,25 @@ var UI = function (_Module) { value: function prepare() { var _this2 = this; - return new Promise(function (resolve, reject) { - - /** - * Element where we need to append CodeX Editor - * @type {Element} - */ - _this2.nodes.holder = document.getElementById(_this2.config.holderId); - - if (!_this2.nodes.holder) { - - reject(Error("Holder wasn't found by ID: #" + _this2.config.holderId)); - return; - } - - /** - * Create and save main UI elements - */ - _this2.nodes.wrapper = $.make('div', CSS.editorWrapper); - _this2.nodes.redactor = $.make('div', CSS.editorZone); - - _this2.nodes.wrapper.appendChild(_this2.nodes.redactor); - _this2.nodes.holder.appendChild(_this2.nodes.wrapper); - - /** - * Make toolbar - */ - _this2.Editor.Toolbar.make(); - /** - * Load and append CSS - */ - _this2.loadStyles(); - - resolve(); + return this.make() + /** + * Make toolbar + */ + .then(function () { + return _this2.Editor.Toolbar.make(); + }) + /** + * Load and append CSS + */ + .then(function () { + return _this2.loadStyles(); + }) + /** + * Bind events for the UI elements + */ + .then(function () { + return _this2.bindEvents(); }) - - /** Add toolbox tools */ - // .then(addTools_) /** Make container for inline toolbar */ // .then(makeInlineToolbar_) @@ -2832,6 +3250,54 @@ var UI = function (_Module) { // editor.core.log("Can't draw editor interface"); }); } + + /** + * CodeX Editor UI CSS class names + * @return {{editorWrapper: string, editorZone: string, block: string}} + */ + + }, { + key: 'make', + + + /** + * Makes CodeX Editor interface + * @return {Promise} + */ + value: function make() { + var _this3 = this; + + return new Promise(function (resolve, reject) { + + /** + * Element where we need to append CodeX Editor + * @type {Element} + */ + _this3.nodes.holder = document.getElementById(_this3.config.holderId); + + if (!_this3.nodes.holder) { + + reject(Error("Holder wasn't found by ID: #" + _this3.config.holderId)); + return; + } + + /** + * Create and save main UI elements + */ + _this3.nodes.wrapper = $.make('div', _this3.CSS.editorWrapper); + _this3.nodes.redactor = $.make('div', _this3.CSS.editorZone); + + _this3.nodes.wrapper.appendChild(_this3.nodes.redactor); + _this3.nodes.holder.appendChild(_this3.nodes.wrapper); + + resolve(); + }); + } + + /** + * Appends CSS + */ + }, { key: 'loadStyles', value: function loadStyles() { @@ -2839,7 +3305,7 @@ var UI = function (_Module) { /** * Load CSS */ - var styles = __webpack_require__(14); + var styles = __webpack_require__(15); /** * Make tag @@ -2853,6 +3319,183 @@ var UI = function (_Module) { */ $.append(document.head, tag); } + + /** + * Bind events on the CodeX Editor interface + */ + + }, { + key: 'bindEvents', + value: function bindEvents() { + var _this4 = this; + + /** + * @todo bind events with the Listeners module + */ + this.nodes.redactor.addEventListener('click', function (event) { + return _this4.redactorClicked(event); + }, false); + } + + /** + * All clicks on the redactor zone + * + * @param {MouseEvent} event + * + * @description + * 1. Save clicked Block as a current {@link BlockManager#currentNode} + * it uses for the following: + * - add CSS modifier for the selected Block + * - on Enter press, we make a new Block under that + * + * 2. Move and show the Toolbar + * + * 3. Set a Caret + * + * 4. By clicks on the Editor's bottom zone: + * - if last Block is empty, set a Caret to this + * - otherwise, add a new empty Block and set a Caret to that + * + * 5. Hide the Inline Toolbar + * + * @see selectClickedBlock + * + */ + + }, { + key: 'redactorClicked', + value: function redactorClicked(event) { + + var clickedNode = event.target; + + /** + * Select clicked Block as Current + */ + try { + + this.Editor.BlockManager.setCurrentBlockByChildNode(clickedNode); + + /** + * If clicked outside first-level Blocks, set Caret to the last empty Block + */ + } catch (e) { + + this.Editor.Caret.setToTheLastBlock(); + } + + /** + * @todo hide the Inline Toolbar + */ + // 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 + */ + this.Editor.Toolbar.move(); + this.Editor.Toolbar.open(); + // + // var inputIsEmpty = !editor.content.currentNode.textContent.trim(), + // currentNodeType = editor.content.currentNode.dataset.tool, + // isInitialType = currentNodeType == editor.settings.initialBlockPlugin; + // + // + + /** + * Hide the Plus Button + * */ + this.Editor.Toolbar.plusButton.hide(); + + /** + * Show the Plus Button if: + * - Block is an initial-block (Text) + * - Block is empty + */ + var isInitialBlock = this.Editor.Tools.isInitial(this.Editor.BlockManager.currentBlock.tool), + isEmptyBlock = this.Editor.BlockManager.currentBlock.isEmpty; + + if (isInitialBlock && isEmptyBlock) { + + this.Editor.Toolbar.plusButton.show(); + } + } + }, { + key: 'CSS', + get: function get() { + + return { + editorWrapper: 'codex-editor', + editorZone: 'codex-editor__redactor' + }; + } }]); return UI; @@ -2886,54 +3529,6 @@ var UI = function (_Module) { // // }; // -// /** -// * @private -// * Append tools passed in editor.tools -// */ -// var addTools_ = function () { -// -// var tool, -// toolName, -// toolButton; -// -// for ( toolName in editor.settings.tools ) { -// -// tool = editor.settings.tools[toolName]; -// -// editor.tools[toolName] = tool; -// -// if (!tool.iconClassname && tool.displayInToolbox) { -// -// editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName); -// continue; -// -// } -// -// if (typeof tool.render != 'function') { -// -// editor.core.log('render method missed. Tool %o skipped', 'warn', toolName); -// continue; -// -// } -// -// if (!tool.displayInToolbox) { -// -// continue; -// -// } else { -// -// /** if tools is for toolbox */ -// toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname); -// -// editor.nodes.toolbox.appendChild(toolButton); -// -// editor.nodes.toolbarButtons[toolName] = toolButton; -// -// } -// -// } -// -// }; // // var addInlineToolbarTools_ = function () { // @@ -3125,24 +3720,24 @@ var UI = function (_Module) { UI.displayName = 'UI'; exports.default = UI; module.exports = exports['default']; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(2))) +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1))) /***/ }), -/* 14 */ +/* 15 */ /***/ (function(module, exports, __webpack_require__) { -exports = module.exports = __webpack_require__(15)(undefined); +exports = module.exports = __webpack_require__(16)(undefined); // imports // module -exports.push([module.i, ":root {\n\n /**\n * Toolbar buttons\n */\n\n}\n/**\n* Editor wrapper\n*/\n.codex-editor{\n position: relative;\n border: 1px solid #ccc;\n padding: 10px;\n}\n.codex-editor .hide {\n display: none;\n }\n", ""]); +exports.push([module.i, ":root {\n\n /**\n * Toolbar buttons\n */\n\n /**\n * Block content width\n */\n\n /**\n * Toolbar Plus Button and Toolbox buttons height and width\n */\n\n}\n/**\n* Editor wrapper\n*/\n.codex-editor {\n position: relative;\n border: 1px solid #ccc;\n padding: 10px;\n box-sizing: border-box;\n}\n.codex-editor .hide {\n display: none;\n }\n.codex-editor__redactor {\n padding-bottom: 300px;\n }\n.ce-toolbar {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n opacity: 0;\n visibility: hidden;\n transition: opacity 100ms ease;\n will-change: opacity, transform;\n}\n.ce-toolbar--opened {\n opacity: 1;\n visibility: visible;\n }\n.ce-toolbar__content {\n max-width: 650px;\n margin: 0 auto;\n position: relative;\n }\n.ce-toolbar__plus {\n position: absolute;\n left: calc(-34px - 10px);\n display: inline-block;\n background-color: #eff2f5;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n border-radius: 50%\n }\n.ce-toolbar__plus::after {\n content: '+';\n font-size: 26px;\n display: block;\n margin-top: -2px;\n margin-right: -2px;\n\n}\n.ce-toolbar__plus--hidden {\n display: none;\n\n}\n.ce-toolbox {\n visibility: hidden;\n transition: opacity 100ms ease;\n will-change: opacity;\n}\n.ce-toolbox--opened {\n opacity: 1;\n visibility: visible;\n }\n.ce-toolbox__button {\n display: inline-block;\n list-style: none;\n margin: 0;\n background: #eff2f5;\n width: 34px;\n height: 34px;\n border-radius: 30px;\n overflow: hidden;\n text-align: center;\n line-height: 34px\n }\n.ce-toolbox__button::before {\n content: attr(title);\n font-size: 22px;\n font-weight: 500;\n letter-spacing: 1em;\n -webkit-font-feature-settings: \"smcp\", \"c2sc\";\n font-feature-settings: \"smcp\", \"c2sc\";\n font-variant-caps: all-small-caps;\n padding-left: 11.5px;\n margin-top: -1px;\n display: inline-block;\n\n}\n.ce-block {\n border: 1px dotted #ccc;\n margin: 2px 0;\n}\n.ce-block--selected {\n background-color: #eff2f5;\n }\n.ce-block__content {\n max-width: 650px;\n margin: 0 auto;\n }\n", ""]); // exports /***/ }), -/* 15 */ +/* 16 */ /***/ (function(module, exports) { /* diff --git a/build/codex-editor.js.map b/build/codex-editor.js.map index 6c4f7a1b..42f74f06 100644 --- a/build/codex-editor.js.map +++ b/build/codex-editor.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap 242085007e0e04e48744","webpack:///./src/components/__module.js","webpack:///./src/components/utils.js","webpack:///./src/components/dom.js","webpack:///./src/codex.js","webpack:///./src/components/modules nonrecursive [^_](blockManager.js|events.js|renderer.js|sanitizer.js|toolbar.js|tools.js|ui.js)$","webpack:///./src/components/modules/blockManager.js","webpack:///./src/components/block.js","webpack:///./src/components/modules/events.js","webpack:///./src/components/modules/renderer.js","webpack:///./src/components/modules/sanitizer.js","webpack:///./node_modules/html-janitor/src/html-janitor.js","webpack:///./src/components/modules/toolbar.js","webpack:///./src/components/modules/tools.js","webpack:///./src/components/modules/ui.js","webpack:///./src/styles/main.css","webpack:///./node_modules/css-loader/lib/css-base.js"],"names":["Module","config","new","target","TypeError","Editor","Util","chains","success","fallback","Promise","resolve","reduce","previousValue","currentValue","iteration","then","waitNextBlock","length","chainData","successCallback","fallbackCallback","function","data","catch","collection","Array","prototype","slice","call","object","Object","keys","constructor","Dom","tagName","classNames","attributes","el","document","createElement","isArray","classList","add","attrName","parent","elements","forEach","appendChild","selector","querySelector","querySelectorAll","node","nodeType","Node","ELEMENT_NODE","modules","editorModules","map","module","exports","moduleInstances","configuration","init","start","console","log","error","constructModules","configureModules","displayName","e","name","state","getModulesDiff","diff","moduleName","prepareDecorator","prepare","UI","Tools","items","Renderer","render","BlockManager","holderId","placeholder","sanitizer","p","b","a","hideToolbar","tools","toolsConfig","_blocks","currentBlockIndex","blocks","Blocks","nodes","redactor","Proxy","set","get","toolName","toolInstance","construct","block","insert","element","index","indexOf","array","workingArea","push","html","replace","remove","deleteCount","splice","previousBlock","insertAdjacentElement","nextBlock","targetBlock","newBlock","_","children","instance","isNaN","Number","Block","tool","CSS","wrapper","content","_html","compose","$","make","Events","subscribers","eventName","callback","previousData","currentHandler","newData","i","insertBlock","sequence","item","type","Sanitizer","defaultConfig","_sanitizerInstance","sanitizerConfig","settings","sanitizerInstance","require","taintString","clean","library","isEmpty","tags","href","rel","customConfig","newInstance","Toolbar","actions","plusButton","toolbox","settingsToggler","removeBlockButton","pluginSettings","defaultSettings","toolbar","append","makeRemoveBlockButton","makeBlockSettingsPanel","toolsAvailable","toolsUnavailable","iconClassName","displayInToolbox","enableLineBreaks","toolClasses","hasOwnProperty","reject","sequenceData","getListOfPrepareFunctions","toolPreparationList","toolClass","toolInstances","plugin","editorWrapper","editorZone","holder","getElementById","Error","loadStyles","styles","tag","textContent","toString","head"],"mappings":"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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;kBAnRqBkF,Q;;;;;;;;;;;;;;;;;;;;;;;ACRrB;;;;;;;;;;;;;;;;;;AAmBA;;;;;;;;;;;;;;;IAeqBoE,S;;;AAEjB;;;;;;;;;AASA,uBAAYrJ,MAAZ,EAAoB;AAAA;;AAIhB;AAJgB,0HAEVA,MAFU;;AAKhB,cAAKsJ,aAAL,GAAqB,IAArB;AACA,cAAKC,kBAAL,GAA0B,IAA1B;;AAEA;AACA,cAAKC,eAAL,GAAuBxJ,OAAOyJ,QAAP,GAAkBzJ,OAAOyJ,QAAP,CAAgBnE,SAAlC,GAA8C,EAArE;;AAEA;AACA,cAAKoE,iBAAL,GAAyB,mBAAAC,CAAQ,EAAR,CAAzB;;AAZgB;AAcnB;;AAED;;;;;;;;;;;;;;;AA0CA;;;;;;8BAMMC,W,EAAa;;AAEf,mBAAO,KAAKL,kBAAL,CAAwBM,KAAxB,CAA8BD,W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;;AA+GhC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;kBApXqB+E,E;;;;;;;;ACzDrB;AACA;;;AAGA;AACA,gCAAiC,iDAAiD,2CAA2C,yBAAyB,6BAA6B,oBAAoB,GAAG,uBAAuB,wBAAwB,OAAO;;AAEhQ;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,mCAAmC,gBAAgB;AACnD,IAAI;AACJ;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,gBAAgB,iBAAiB;AACjC;AACA;AACA;AACA;AACA,YAAY,oBAAoB;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,oDAAoD,cAAc;;AAElE;AACA","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 \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\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.l = 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// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 3);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 242085007e0e04e48744","/**\n * @abstract\n * @class Module\n * @classdesc All modules inherites from this class.\n *\n * @typedef {Module} Module\n * @property {Object} config - Editor user settings\n * @property {Object} Editor - List of Editor modules\n */\nexport default class Module {\n\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor({ config } = {}) {\n\n if (new.target === Module) {\n\n throw new TypeError('Constructors for abstract class Module are not allowed.');\n\n }\n\n this.config = config;\n this.Editor = null;\n\n }\n\n /**\n * Editor modules setter\n *\n * @param Editor\n * @param Editor.modules {@link CodexEditor#moduleInstances}\n * @param Editor.config {@link CodexEditor#configuration}\n */\n set state(Editor) {\n\n this.Editor = Editor;\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/__module.js","/**\n * Codex Editor Util\n */\nexport default class Util {\n\n /**\n * @typedef {Object} ChainData\n * @property {Object} data - data that will be passed to the success or fallback\n * @property {Function} function - function's that must be called asynchronically\n */\n\n /**\n * Fires a promise sequence asyncronically\n *\n * @param {Object[]} chains - list or ChainData's\n * @param {Function} success - success callback\n * @param {Function} fallback - callback that fires in case of errors\n *\n * @return {Promise}\n */\n static sequence(chains, success = () => {}, fallback = () => {}) {\n\n return new Promise(function (resolve) {\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 chains.reduce(function (previousValue, currentValue, iteration) {\n\n return previousValue\n .then(() => waitNextBlock(currentValue, success, fallback))\n .then(() => {\n\n // finished\n if (iteration === chains.length - 1) {\n\n resolve();\n\n }\n\n });\n\n }, Promise.resolve());\n\n });\n\n /**\n * Decorator\n *\n * @param {ChainData} chainData\n *\n * @param {Function} successCallback\n * @param {Function} fallbackCallback\n *\n * @return {Promise}\n */\n function waitNextBlock(chainData, successCallback, fallbackCallback) {\n\n return new Promise(function (resolve) {\n\n chainData.function()\n .then(() => {\n\n successCallback(chainData.data);\n\n })\n .then(resolve)\n .catch(function () {\n\n fallbackCallback(chainData.data);\n\n // anyway, go ahead even it falls\n resolve();\n\n });\n\n });\n\n }\n\n }\n\n /**\n * Make array from array-like collection\n *\n * @param {*} collection\n *\n * @return {Array}\n */\n static array(collection) {\n\n return Array.prototype.slice.call(collection);\n\n }\n\n /**\n * Checks if object is empty\n *\n * @param {Object} object\n * @return {boolean}\n */\n static isEmpty(object) {\n\n return Object.keys(object).length === 0 && object.constructor === Object;\n\n }\n\n};\n\n\n// WEBPACK FOOTER //\n// ./src/components/utils.js","/**\n * DOM manupulations helper\n */\nexport default class Dom {\n\n /**\n * Helper for making Elements with classname and attributes\n *\n * @param {string} tagName - new Element tag name\n * @param {array|string} classNames - list or name of CSS classname(s)\n * @param {Object} attributes - any attributes\n * @return {Element}\n */\n static make(tagName, classNames = null, attributes = {}) {\n\n var el = document.createElement(tagName);\n\n if ( Array.isArray(classNames) ) {\n\n el.classList.add(...classNames);\n\n } else if( classNames ) {\n\n el.classList.add(classNames);\n\n }\n\n for (let attrName in attributes) {\n\n el[attrName] = attributes[attrName];\n\n }\n\n return el;\n\n }\n\n /**\n * Append one or several elements to the parent\n *\n * @param {Element} parent - where to append\n * @param {Element|Element[]} - element ore elements list\n */\n static append(parent, elements) {\n\n if ( Array.isArray(elements) ) {\n\n elements.forEach( el => parent.appendChild(el) );\n\n } else {\n\n parent.appendChild(elements);\n\n }\n\n }\n\n /**\n * Selector Decorator\n *\n * Returns first match\n *\n * @param {Element} el - element we searching inside. Default - DOM Document\n * @param {String} selector - searching string\n *\n * @returns {Element}\n */\n static find(el = document, selector) {\n\n return el.querySelector(selector);\n\n }\n\n /**\n * Selector Decorator.\n *\n * Returns all matches\n *\n * @param {Element} el - element we searching inside. Default - DOM Document\n * @param {String} selector - searching string\n * @returns {NodeList}\n */\n static findAll(el = document, selector) {\n\n return el.querySelectorAll(selector);\n\n }\n\n /**\n * Check if object is DOM node\n *\n * @param {Object} node\n * @returns {boolean}\n */\n static isNode(node) {\n\n return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE;\n\n }\n\n};\n\n\n// WEBPACK FOOTER //\n// ./src/components/dom.js","/**\n * Codex Editor\n *\n * Short Description (눈_눈;)\n * @version 2.0.0\n *\n * How to start?\n * Example:\n * new CodexEditor({\n * holderId : 'codex-editor',\n * initialBlock : 'paragraph',\n * placeholder : 'Write your story....',\n * tools: {\n * quote: Quote,\n * anotherTool : AnotherTool\n * },\n * toolsConfig: {\n * quote: {\n * iconClassname : 'quote-icon',\n * displayInToolbox : true,\n * enableLineBreaks : true\n * },\n * anotherTool: {\n * iconClassname : 'tool-icon'\n * }\n * }\n * });\n *\n * - tools is an object: {\n * pluginName: PluginClass,\n * .....\n * }\n * - toolsConfig is an additional configuration that uses Codex Editor API\n * iconClassname - CSS classname of toolbox icon\n * displayInToolbox - if you want to see your Tool in toolbox hided in \"plus\" button, than set \"True\". By default : \"False\"\n * enableLineBreaks - by default enter creates new block that set as initialblock, but if you set this property \"True\", enter will break the lines in current block\n *\n * @author CodeX-Team \n *\n */\n\n/**\n * @typedef {CodexEditor} CodexEditor - editor class\n */\n\n/**\n * @typedef {Object} EditorConfig\n * @property {String} holderId - Element to append Editor\n * @property {String} initialBlock - Tool name which will be initial\n * @property {Object} tools - list of tools. The object value must be function (constructor) so that CodexEditor could make an instance\n * @property {@link Tools#ToolsConfig} toolsConfig - tools configuration\n * @property {Array} data - Blocks list in JSON-format\n */\n\n'use strict';\n\n/**\n * Require Editor modules places in components/modules dir\n */\n// eslint-disable-next-line\nlet modules = editorModules.map( module => require('./components/modules/' + module ));\n\n/**\n * @class\n *\n * @classdesc CodeX Editor base class\n *\n * @property this.config - all settings\n * @property this.moduleInstances - constructed editor components\n *\n * @type {CodexEditor}\n */\nmodule.exports = class CodexEditor {\n\n /** Editor version */\n static get version() {\n\n return VERSION;\n\n }\n\n /**\n * @param {EditorConfig} config - user configuration\n *\n */\n constructor(config) {\n\n /**\n * Configuration object\n */\n this.config = {};\n\n /**\n * Editor Components\n */\n this.moduleInstances = {};\n\n Promise.resolve()\n .then(() => {\n\n this.configuration = config;\n\n })\n .then(() => this.init())\n .then(() => this.start())\n .then(() => {\n\n console.log('CodeX Editor is ready');\n\n })\n .catch(error => {\n\n console.log('CodeX Editor does not ready beecause of %o', error);\n\n });\n\n }\n\n /**\n * Setting for configuration\n * @param {Object} config\n */\n set configuration(config = {}) {\n\n this.config.holderId = config.holderId;\n this.config.placeholder = config.placeholder || 'write your story...';\n this.config.sanitizer = config.sanitizer || {\n p: true,\n b: true,\n a: true\n };\n\n this.config.hideToolbar = config.hideToolbar ? config.hideToolbar : false;\n this.config.tools = config.tools || {};\n this.config.toolsConfig = config.toolsConfig || {};\n this.config.data = config.data || [];\n\n }\n\n /**\n * Returns private property\n * @returns {{}|*}\n */\n get configuration() {\n\n return this.config;\n\n }\n\n /**\n * Initializes modules:\n * - make and save instances\n * - configure\n */\n init() {\n\n /**\n * Make modules instances and save it to the @property this.moduleInstances\n */\n this.constructModules();\n\n /**\n * Modules configuration\n */\n this.configureModules();\n\n }\n\n /**\n * Make modules instances and save it to the @property this.moduleInstances\n */\n constructModules() {\n\n modules.forEach( Module => {\n\n try {\n\n /**\n * We use class name provided by displayName property\n *\n * On build, Babel will transform all Classes to the Functions so, name will always be 'Function'\n * To prevent this, we use 'babel-plugin-class-display-name' plugin\n * @see https://www.npmjs.com/package/babel-plugin-class-display-name\n */\n\n this.moduleInstances[Module.displayName] = new Module({\n config : this.configuration\n });\n\n } catch ( e ) {\n\n console.log('Module %o skipped because %o', Module, e);\n\n }\n\n });\n\n }\n\n /**\n * Modules instances configuration:\n * - pass other modules to the 'state' property\n * - ...\n */\n configureModules() {\n\n for(let name in this.moduleInstances) {\n\n /**\n * Module does not need self-instance\n */\n this.moduleInstances[name].state = this.getModulesDiff( name );\n\n }\n\n }\n\n /**\n * Return modules without passed name\n */\n getModulesDiff( name ) {\n\n let diff = {};\n\n for(let moduleName in this.moduleInstances) {\n\n /**\n * Skip module with passed name\n */\n if (moduleName === name) {\n\n continue;\n\n }\n diff[moduleName] = this.moduleInstances[moduleName];\n\n }\n\n return diff;\n\n }\n\n /**\n * Start Editor!\n *\n * @return {Promise}\n */\n start() {\n\n let prepareDecorator = module => module.prepare();\n\n return Promise.resolve()\n .then(prepareDecorator(this.moduleInstances.UI))\n .then(prepareDecorator(this.moduleInstances.Tools))\n .then(() => {\n\n if (this.config.data && this.config.data.items) {\n\n this.moduleInstances.Renderer.render(this.config.data.items);\n\n }\n\n })\n .then(prepareDecorator(this.moduleInstances.BlockManager))\n\n .catch(function (error) {\n\n console.log('Error occured', error);\n\n });\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// 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// ./src/codex.js","var map = {\n\t\"./blockManager.js\": 5,\n\t\"./events.js\": 7,\n\t\"./renderer.js\": 8,\n\t\"./sanitizer.js\": 9,\n\t\"./toolbar.js\": 11,\n\t\"./tools.js\": 12,\n\t\"./ui.js\": 13\n};\nfunction webpackContext(req) {\n\treturn __webpack_require__(webpackContextResolve(req));\n};\nfunction webpackContextResolve(req) {\n\tvar id = map[req];\n\tif(!(id + 1)) // check for number or string\n\t\tthrow new Error(\"Cannot find module '\" + req + \"'.\");\n\treturn id;\n};\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = 4;\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/components/modules nonrecursive [^_](blockManager.js|events.js|renderer.js|sanitizer.js|toolbar.js|tools.js|ui.js)$\n// module id = 4\n// module chunks = 0","/**\n * @class BlockManager\n * @classdesc Manage editor`s blocks storage and appearance\n *\n * @module BlockManager\n */\n\nimport Block from '../block';\n\nexport default class BlockManager extends Module {\n\n /**\n * @constructor\n * @param {EditorConfig} config\n */\n constructor(config) {\n\n super(config);\n\n /**\n * Proxy for Blocks instance {@link Blocks}\n *\n * @type {Proxy}\n * @private\n */\n this._blocks = null;\n\n /**\n * Index of current working block\n *\n * @type {number}\n * @private\n */\n this.currentBlockIndex = -1;\n\n }\n\n /**\n * Should be called after Editor.UI preparation\n * Define this._blocks property\n *\n * @returns {Promise}\n */\n prepare() {\n\n return new Promise(resolve => {\n\n let blocks = new Blocks(this.Editor.UI.nodes.redactor);\n\n /**\n * We need to use Proxy to overload set/get [] operator.\n * So we can use array-like syntax to access blocks\n *\n * @example\n * this._blocks[0] = new Block(...);\n *\n * block = this._blocks[0];\n *\n * @todo proxy the enumerate method\n *\n * @type {Proxy}\n * @private\n */\n this._blocks = new Proxy(blocks, {\n set: Blocks.set,\n get: Blocks.get\n });\n\n resolve();\n\n });\n\n }\n\n /**\n * Insert new block into _blocks\n *\n * @param {String} toolName — plugin name\n * @param {Object} data — plugin data\n */\n insert(toolName, data) {\n\n let toolInstance = this.Editor.Tools.construct(toolName, data),\n block = new Block(toolInstance);\n\n this._blocks[++this.currentBlockIndex] = block;\n\n }\n\n /**\n * Replace current working block\n *\n * @param {String} toolName — plugin name\n * @param {Object} data — plugin data\n */\n replace(toolName, data) {\n\n let toolInstance = this.Editor.Tools.construct(toolName, data),\n block = new Block(toolInstance);\n\n this._blocks.insert(this.currentBlockIndex, block, true);\n\n }\n\n /**\n * Get Block instance by html element\n *\n * @todo get first level block before searching\n *\n * @param {HTMLElement} element\n * @returns {Block}\n */\n getBlock(element) {\n\n let nodes = this._blocks.nodes,\n index = nodes.indexOf(element);\n\n if (index >= 0) {\n\n return this._blocks[index];\n\n }\n\n }\n\n /**\n * Get current Block instance\n *\n * @return {Block}\n */\n get currentBlock() {\n\n return this._blocks[this.currentBlockIndex];\n\n }\n\n /**\n * Get working html element\n *\n * @return {HTMLElement}\n */\n get currentNode() {\n\n return this._blocks.nodes[this.currentBlockIndex];\n\n }\n\n /**\n * Set currentBlockIndex to passed block\n *\n * @todo get first level block before searching\n *\n * @param {HTMLElement} element\n */\n set currentNode(element) {\n\n let nodes = this._blocks.nodes;\n\n this.currentBlockIndex = nodes.indexOf(element);\n\n }\n\n /**\n * Get array of Block instances\n *\n * @returns {Block[]} {@link Blocks#array}\n */\n get blocks() {\n\n return this._blocks.array;\n\n }\n\n}\n\n/**\n * @class Blocks\n * @classdesc Class to work with Block instances array\n *\n * @private\n *\n * @property {HTMLElement} workingArea — editor`s working node\n *\n */\nclass Blocks {\n\n /**\n * @constructor\n *\n * @param {HTMLElement} workingArea — editor`s working node\n */\n constructor(workingArea) {\n\n this.blocks = [];\n this.workingArea = workingArea;\n\n }\n\n /**\n * Push back new Block\n *\n * @param {Block} block\n */\n push(block) {\n\n this.blocks.push(block);\n this.workingArea.appendChild(block.html);\n\n }\n\n /**\n * Insert new Block at passed index\n *\n * @param {Number} index — index to insert Block\n * @param {Block} block — Block to insert\n * @param {Boolean} replace — it true, replace block on given index\n */\n insert(index, block, replace = false) {\n\n if (!this.length) {\n\n this.push(block);\n return;\n\n }\n\n if (index > this.length) {\n\n index = this.length;\n\n }\n\n if (replace) {\n\n this.blocks[index].html.remove();\n\n }\n\n let deleteCount = replace ? 1 : 0;\n\n this.blocks.splice(index, deleteCount, block);\n\n if (index > 0) {\n\n let previousBlock = this.blocks[index - 1];\n\n previousBlock.html.insertAdjacentElement('afterend', block.html);\n\n } else {\n\n let nextBlock = this.blocks[index + 1];\n\n if (nextBlock) {\n\n nextBlock.html.insertAdjacentElement('beforebegin', block.html);\n\n } else {\n\n this.workingArea.appendChild(block.html);\n\n }\n\n }\n\n }\n\n /**\n * Insert Block after passed target\n *\n * @todo decide if this method is necessary\n *\n * @param {Block} targetBlock — target after wich Block should be inserted\n * @param {Block} newBlock — Block to insert\n */\n insertAfter(targetBlock, newBlock) {\n\n let index = this.blocks.indexOf(targetBlock);\n\n this.insert(index + 1, newBlock);\n\n }\n\n /**\n * Get Block by index\n *\n * @param {Number} index — Block index\n * @returns {Block}\n */\n get(index) {\n\n return this.blocks[index];\n\n }\n\n /**\n * Return index of passed Block\n *\n * @param {Block} block\n * @returns {Number}\n */\n indexOf(block) {\n\n return this.blocks.indexOf(block);\n\n }\n\n /**\n * Get length of Block instances array\n *\n * @returns {Number}\n */\n get length() {\n\n return this.blocks.length;\n\n }\n\n /**\n * Get Block instances array\n *\n * @returns {Block[]}\n */\n get array() {\n\n return this.blocks;\n\n }\n\n /**\n * Get blocks html elements array\n *\n * @returns {HTMLElement[]}\n */\n get nodes() {\n\n return _.array(this.workingArea.children);\n\n }\n\n /**\n * Proxy trap to implement array-like setter\n *\n * @example\n * blocks[0] = new Block(...)\n *\n * @param {Blocks} instance — Blocks instance\n * @param {Number|String} index — block index\n * @param {Block} block — Block to set\n * @returns {Boolean}\n */\n static set(instance, index, block) {\n\n if (isNaN(Number(index))) {\n\n return false;\n\n }\n\n instance.insert(index, block);\n\n return true;\n\n }\n\n /**\n * Proxy trap to implement array-like getter\n *\n * @param {Blocks} instance — Blocks instance\n * @param {Number|String} index — Block index\n * @returns {Block|*}\n */\n static get(instance, index) {\n\n if (isNaN(Number(index))) {\n\n return instance[index];\n\n }\n\n return instance.get(index);\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/blockManager.js","/**\n *\n * @class Block\n * @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool\n *\n * @property {Tool} tool — current block tool (Paragraph, for example)\n * @property {Object} CSS — block`s css classes\n *\n */\n\n\nexport default class Block {\n\n /**\n * @constructor\n *\n * @param {Object} tool — current block plugin`s instance\n */\n constructor(tool) {\n\n this.tool = tool;\n\n this.CSS = {\n wrapper: 'ce-block',\n content: 'ce-block__content'\n };\n\n this._html = this.compose();\n\n }\n\n /**\n * Make default block wrappers and put tool`s content there\n *\n * @returns {HTMLDivElement}\n * @private\n */\n compose() {\n\n let wrapper = $.make('div', this.CSS.wrapper),\n content = $.make('div', this.CSS.content);\n\n content.appendChild(this.tool.html);\n wrapper.appendChild(content);\n\n return wrapper;\n\n }\n\n /**\n * Get block`s HTML\n *\n * @returns {HTMLDivElement}\n */\n get html() {\n\n return this._html;\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/block.js","/**\n * @module eventDispatcher\n *\n * Has two important methods:\n * - {Function} on - appends subscriber to the event. If event doesn't exist - creates new one\n * - {Function} emit - fires all subscribers with data\n *\n * @version 1.0.0\n *\n * @typedef {Events} Events\n * @property {Object} subscribers - all subscribers grouped by event name\n */\nexport default class Events extends Module {\n\n /**\n * @constructor\n */\n constructor(config) {\n\n super(config);\n this.subscribers = {};\n\n }\n\n /**\n * @param {String} eventName - event name\n * @param {Function} callback - subscriber\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 /**\n * @param {String} eventName - event name\n * @param {Object} data - subscribers get this data when they were fired\n */\n emit(eventName, data) {\n\n this.subscribers[eventName].reduce(function (previousData, currentHandler) {\n\n let newData = currentHandler(previousData);\n\n return newData ? newData : previousData;\n\n }, data);\n\n }\n\n /**\n * Destroyer\n * clears subsribers list\n */\n destroy() {\n\n this.subscribers = null;\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/events.js","/**\n * Codex Editor Renderer Module\n *\n * @module Renderer\n * @author CodeX Team\n *\n * @version 2.0.0\n */\nexport default class Renderer extends Module {\n\n /**\n * @constructor\n * @param {EditorConfig} config\n */\n constructor(config) {\n\n super(config);\n\n }\n\n /**\n * @typedef {Object} RendererItems\n * @property {String} type - tool name\n * @property {Object} data - tool data\n */\n\n /**\n * @example\n *\n * items: [\n * {\n * type : 'paragraph',\n * data : {\n * text : 'Hello from Codex!'\n * }\n * },\n * {\n * type : 'paragraph',\n * data : {\n * text : 'Leave feedback if you like it!'\n * }\n * },\n * ]\n *\n */\n\n /**\n * Make plugin blocks from array of plugin`s data\n * @param {RendererItems[]} items\n */\n render(items) {\n\n let chainData = [];\n\n for (let i = 0; i < items.length; i++) {\n\n chainData.push({\n function: () => this.insertBlock(items[i])\n });\n\n }\n\n _.sequence(chainData);\n\n }\n\n /**\n * Get plugin instance\n * Add plugin instance to BlockManager\n * Insert block to working zone\n *\n * @param {Object} item\n * @returns {Promise.}\n * @private\n */\n insertBlock(item) {\n\n let tool = item.type,\n data = item.data;\n\n this.Editor.BlockManager.insert(tool, data);\n\n return Promise.resolve();\n\n }\n\n}\n\n// module.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 Promise -> 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// ./src/components/modules/renderer.js","/**\n * CodeX Sanitizer\n *\n * @module Sanitizer\n * Clears HTML from taint tags\n *\n * @version 2.0.0\n *\n * @example\n * Module can be used within two ways:\n * 1) When you have an instance\n * - this.Editor.Sanitizer.clean(yourTaintString);\n * 2) As static method\n * - CodexEditor.Sanitizer.clean(yourTaintString, yourCustomConfiguration);\n *\n * {@link SanitizerConfig}\n */\n\n\n/**\n * @typedef {Object} SanitizerConfig\n * @property {Object} tags - define tags restrictions\n *\n * @example\n *\n * tags : {\n * p: true,\n * a: {\n * href: true,\n * rel: \"nofollow\",\n * target: \"_blank\"\n * }\n * }\n */\nexport default class Sanitizer extends Module {\n\n /**\n * Initializes Sanitizer module\n * Sets default configuration if custom not exists\n *\n * @property {SanitizerConfig} this.defaultConfig\n * @property {HTMLJanitor} this._sanitizerInstance - Sanitizer library\n *\n * @param {SanitizerConfig} config\n */\n constructor(config) {\n\n super(config);\n\n // default config\n this.defaultConfig = null;\n this._sanitizerInstance = null;\n\n /** Custom configuration */\n this.sanitizerConfig = config.settings ? config.settings.sanitizer : {};\n\n /** HTML Janitor library */\n this.sanitizerInstance = require('html-janitor');\n\n }\n\n /**\n * If developer uses editor's API, then he can customize sanitize restrictions.\n * Or, sanitizing 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 Default configuration\n *\n * @uses https://www.npmjs.com/package/html-janitor\n *\n * @param {HTMLJanitor} library - sanitizer extension\n */\n set sanitizerInstance(library) {\n\n this._sanitizerInstance = new library(this.defaultConfig);\n\n }\n\n /**\n * Sets sanitizer configuration. Uses default config if user didn't pass the restriction\n * @param {SanitizerConfig} config\n */\n set sanitizerConfig(config) {\n\n if (_.isEmpty(config)) {\n\n this.defaultConfig = {\n tags: {\n p: {},\n a: {\n href: true,\n target: '_blank',\n rel: 'nofollow'\n }\n }\n };\n\n } else {\n\n this.defaultConfig = config;\n\n }\n\n }\n\n /**\n * Cleans string from unwanted tags\n * @param {String} taintString - HTML string\n *\n * @return {String} clean HTML\n */\n clean(taintString) {\n\n return this._sanitizerInstance.clean(taintString);\n\n }\n\n /**\n * Cleans string from unwanted tags\n * @static\n *\n * Method allows to use default config\n *\n * @param {String} taintString - taint string\n * @param {SanitizerConfig} customConfig - allowed tags\n *\n * @return {String} clean HTML\n */\n static clean(taintString, customConfig) {\n\n let newInstance = Sanitizer(customConfig);\n\n return newInstance.clean(taintString);\n\n }\n\n}\n\n\n\n// WEBPACK FOOTER //\n// ./src/components/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// ./node_modules/html-janitor/src/html-janitor.js\n// module id = 10\n// module chunks = 0","/**\n *\n * «Toolbar» is the node that moves up/down over current block\n *\n * ______________________________________ Toolbar ____________________________________________\n * | |\n * | ..................... Content .................... ......... Block Actions .......... |\n * | . . . . |\n * | . . . [Open Settings] [Remove Block] . |\n * | . [Plus Button] [Toolbox: {Tool1}, {Tool2}] . . . |\n * | . . . [Settings Panel] . |\n * | .................................................. .................................. |\n * | |\n * |___________________________________________________________________________________________|\n *\n *\n * Toolbox — its an Element contains tools buttons. Can be shown by Plus Button.\n *\n * _______________ Toolbox _______________\n * | |\n * | [Header] [Image] [List] [Quote] ... |\n * |_______________________________________|\n *\n *\n * Settings Panel — is an Element with block settings:\n *\n * ____ Settings Panel ____\n * | ...................... |\n * | . Tool Settings . |\n * | ...................... |\n * | . Default Settings . |\n * | ...................... |\n * |________________________|\n *\n *\n * @class\n * @classdesc Toolbar module\n *\n * @typedef {Toolbar} Toolbar\n * @property {Object} nodes\n * @property {Element} nodes.wrapper - Toolbar main element\n * @property {Element} nodes.content - Zone with Plus button and toolbox.\n * @property {Element} nodes.actions - Zone with Block Settings and Remove Button\n * @property {Element} nodes.plusButton - Button that opens or closes Toolbox\n * @property {Element} nodes.toolbox - Container for tools\n * @property {Element} nodes.settingsToggler - open/close Settings Panel button\n * @property {Element} nodes.removeBlockButton - Remove Block button\n * @property {Element} nodes.settings - Settings Panel\n * @property {Element} nodes.pluginSettings - Plugin Settings section of Settings Panel\n * @property {Element} nodes.defaultSettings - Default Settings section of Settings Panel\n */\nexport default class Toolbar extends Module {\n\n /**\n * @constructor\n */\n constructor(config) {\n\n super(config);\n\n this.nodes = {\n wrapper : null,\n content : null,\n actions : null,\n\n // Content Zone\n plusButton : null,\n toolbox : null,\n\n // Actions Zone\n settingsToggler : null,\n removeBlockButton: null,\n settings: null,\n\n // Settings Zone: Plugin Settings and Default Settings\n pluginSettings: null,\n defaultSettings: null,\n };\n\n this.CSS = {\n toolbar: 'ce-toolbar',\n content: 'ce-toolbar__content',\n actions: 'ce-toolbar__actions',\n\n // Content Zone\n toolbox: 'ce-toolbar__toolbox',\n plusButton: 'ce-toolbar__plus',\n\n // Actions Zone\n settingsToggler: 'ce-toolbar__settings-btn',\n removeBlockButton: 'ce-toolbar__remove-btn',\n\n // Settings Panel\n settings: 'ce-settings',\n defaultSettings: 'ce-settings_default',\n pluginSettings: 'ce-settings_plugin',\n };\n\n }\n\n /**\n * Makes toolbar\n */\n make() {\n\n this.nodes.wrapper = $.make('div', this.CSS.toolbar);\n\n /**\n * Make Content Zone and Actions Zone\n */\n ['content', 'actions'].forEach( el => {\n\n this.nodes[el] = $.make('div', this.CSS[el]);\n $.append(this.nodes.wrapper, this.nodes[el]);\n\n });\n\n\n /**\n * Fill Content Zone:\n * - Plus Button\n * - Toolbox\n */\n ['plusButton', 'toolbox'].forEach( el => {\n\n this.nodes[el] = $.make('div', this.CSS[el]);\n $.append(this.nodes.content, this.nodes[el]);\n\n });\n\n /**\n * Fill Actions Zone:\n * - Settings Toggler\n * - Remove Block Button\n * - Settings Panel\n */\n this.nodes.settingsToggler = $.make('span', this.CSS.settingsToggler);\n this.nodes.removeBlockButton = this.makeRemoveBlockButton();\n\n $.append(this.nodes.actions, [this.nodes.settingsToggler, this.nodes.removeBlockButton]);\n\n /**\n * Make and append Settings Panel\n */\n this.makeBlockSettingsPanel();\n\n /**\n * Append toolbar to the Editor\n */\n $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);\n\n }\n\n /**\n * Panel with block settings with 2 sections:\n *\n * @return {Element}\n */\n makeBlockSettingsPanel() {\n\n this.nodes.settings = $.make('div', this.CSS.settings);\n\n this.nodes.pluginSettings = $.make('div', this.CSS.pluginSettings);\n this.nodes.defaultSettings = $.make('div', this.CSS.defaultSettings);\n\n $.append(this.nodes.settings, [this.nodes.pluginSettings, this.nodes.defaultSettings]);\n $.append(this.nodes.actions, this.nodes.settings);\n\n }\n\n /**\n * Makes Remove Block button, and confirmation panel\n * @return {Element} wrapper with button and panel\n */\n makeRemoveBlockButton() {\n\n /**\n * @todo add confirmation panel and handlers\n * @see {@link settings#makeRemoveBlockButton}\n */\n return $.make('span', this.CSS.removeBlockButton);\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/toolbar.js","/**\n * @module Codex Editor Tools Submodule\n *\n * Creates Instances from Plugins and binds external config to the instances\n */\n\n/**\n * Load user defined tools\n * Tools must contain the following important objects:\n *\n * @typedef {Object} ToolsConfig\n * @property {String} iconClassname - this a icon in toolbar\n * @property {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\n * @property {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\n * @property render @todo add description\n * @property save @todo add description\n * @property settings @todo add description\n * @property validate - method that validates output data before saving\n */\n\n/**\n * @typedef {Tool} Tool\n * @property {String} name - name of this module\n * @property {Object[]} toolInstances - list of tool instances\n * @property {Tools[]} available - available Tools\n * @property {Tools[]} unavailable - unavailable Tools\n * @property {Object} toolsClasses - all classes\n * @property {EditorConfig} config - Editor config\n */\n\nexport default class Tools extends Module {\n\n /**\n * Returns available Tools\n * @return {Tool[]}\n */\n get available() {\n\n return this.toolsAvailable;\n\n }\n\n /**\n * Returns unavailable Tools\n * @return {Tool[]}\n */\n get unavailable() {\n\n return this.toolsUnavailable;\n\n }\n\n /**\n * If config wasn't passed by user\n * @return {ToolsConfig}\n */\n get defaultConfig() {\n\n return {\n iconClassName : 'default-icon',\n displayInToolbox : false,\n enableLineBreaks : false\n };\n\n }\n\n /**\n * @constructor\n *\n * @param {ToolsConfig} config\n */\n constructor(config) {\n\n super(config);\n\n this.toolClasses = {};\n this.toolsAvailable = {};\n this.toolsUnavailable = {};\n\n }\n\n /**\n * Creates instances via passed or default configuration\n * @return {boolean}\n */\n prepare() {\n\n if (!this.config.hasOwnProperty('tools')) {\n\n return Promise.reject(\"Can't start without tools\");\n\n }\n\n for(let toolName in this.config.tools) {\n\n this.toolClasses[toolName] = this.config.tools[toolName];\n\n }\n\n /**\n * getting classes that has prepare method\n */\n let sequenceData = this.getListOfPrepareFunctions();\n\n /**\n * if sequence data contains nothing then resolve current chain and run other module prepare\n */\n if (sequenceData.length === 0) {\n\n return Promise.resolve();\n\n }\n\n /**\n * to see how it works {@link Util#sequence}\n */\n return _.sequence(sequenceData, (data) => {\n\n this.success(data);\n\n }, (data) => {\n\n this.fallback(data);\n\n });\n\n }\n\n /**\n * Binds prepare function of plugins with user or default config\n * @return {Array} list of functions that needs to be fired sequently\n */\n getListOfPrepareFunctions() {\n\n let toolPreparationList = [];\n\n for(let toolName in this.toolClasses) {\n\n let toolClass = this.toolClasses[toolName];\n\n if (typeof toolClass.prepare === 'function') {\n\n toolPreparationList.push({\n function : toolClass.prepare,\n data : {\n toolName\n }\n });\n\n }\n\n }\n\n return toolPreparationList;\n\n }\n\n /**\n * @param {ChainData.data} data - append tool to available list\n */\n success(data) {\n\n this.toolsAvailable[data.toolName] = this.toolClasses[data.toolName];\n\n }\n\n /**\n * @param {ChainData.data} data - append tool to unavailable list\n */\n fallback(data) {\n\n this.toolsUnavailable[data.toolName] = this.toolClasses[data.toolName];\n\n }\n\n /**\n * Returns all tools\n * @return {Array}\n */\n getTools() {\n\n return this.toolInstances;\n\n }\n\n /**\n * Return tool`a instance\n *\n * @param {String} tool — tool name\n * @param {Object} data — initial data\n *\n * @todo throw exceptions if tool doesnt exist\n *\n */\n construct(tool, data) {\n\n let plugin = this.toolClasses[tool],\n config = this.config.toolsConfig[tool];\n\n if (!config) {\n\n config = this.defaultConfig;\n\n }\n\n let instance = new plugin(data, config);\n\n return instance;\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/tools.js","/**\n * Module UI\n *\n * @type {UI}\n */\n// let className = {\n\n/**\n * @const {string} BLOCK_CLASSNAME - redactor blocks name\n */\n// BLOCK_CLASSNAME : 'ce-block',\n\n/**\n * @const {String} wrapper for plugins content\n */\n// BLOCK_CONTENT : 'ce-block__content',\n\n/**\n * @const {String} BLOCK_STRETCHED - makes block stretched\n */\n// BLOCK_STRETCHED : 'ce-block--stretched',\n\n/**\n * @const {String} BLOCK_HIGHLIGHTED - adds background\n */\n// BLOCK_HIGHLIGHTED : 'ce-block--focused',\n\n/**\n * @const {String} - for all default settings\n */\n// SETTINGS_ITEM : 'ce-settings__item'\n// };\n\nlet CSS = {\n editorWrapper : 'codex-editor',\n editorZone : 'ce-redactor'\n};\n\n/**\n * @class\n *\n * @classdesc Makes CodeX Editor UI:\n * \n * \n * \n * \n * \n *\n * @typedef {UI} UI\n * @property {EditorConfig} config - editor configuration {@link CodexEditor#configuration}\n * @property {Object} Editor - available editor modules {@link CodexEditor#moduleInstances}\n * @property {Object} nodes -\n * @property {Element} nodes.holder - element where we need to append redactor\n * @property {Element} nodes.wrapper - \n * @property {Element} nodes.redactor - \n */\n\nexport default class UI extends Module {\n\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor(config) {\n\n super(config);\n\n this.nodes = {\n holder: null,\n wrapper: null,\n redactor: null\n };\n\n }\n\n /**\n * @protected\n *\n * Making main interface\n */\n prepare() {\n\n return new Promise( (resolve, reject) => {\n\n /**\n * Element where we need to append CodeX Editor\n * @type {Element}\n */\n this.nodes.holder = document.getElementById(this.config.holderId);\n\n if (!this.nodes.holder) {\n\n reject(Error(\"Holder wasn't found by ID: #\" + this.config.holderId));\n return;\n\n }\n\n /**\n * Create and save main UI elements\n */\n this.nodes.wrapper = $.make('div', CSS.editorWrapper);\n this.nodes.redactor = $.make('div', CSS.editorZone);\n\n this.nodes.wrapper.appendChild(this.nodes.redactor);\n this.nodes.holder.appendChild(this.nodes.wrapper);\n\n /**\n * Make toolbar\n */\n this.Editor.Toolbar.make();\n /**\n * Load and append CSS\n */\n this.loadStyles();\n\n resolve();\n\n })\n\n /** Add toolbox tools */\n // .then(addTools_)\n\n /** Make container for inline toolbar */\n // .then(makeInlineToolbar_)\n\n /** Add inline toolbar tools */\n // .then(addInlineToolbarTools_)\n\n /** Draw wrapper for notifications */\n // .then(makeNotificationHolder_)\n\n /** Add eventlisteners to redactor elements */\n // .then(bindEvents_)\n\n .catch(e => {\n\n console.error(e);\n\n // editor.core.log(\"Can't draw editor interface\");\n\n });\n\n }\n\n loadStyles() {\n\n /**\n * Load CSS\n */\n let styles = require('../../styles/main.css');\n\n /**\n * Make tag\n */\n let tag = $.make('style', null, {\n textContent: styles.toString()\n });\n\n /**\n * Append styles\n */\n $.append(document.head, tag);\n\n }\n\n}\n\n// /**\n// * Codex Editor UI module\n// *\n// * @author Codex Team\n// * @version 1.2.0\n// */\n//\n// module.exports = (function (ui) {\n//\n// let editor = codex.editor;\n//\n// /**\n// * Basic editor classnames\n// */\n// ui.prepare = function () {\n//\n\n//\n// };\n//\n// /** Draw notifications holder */\n// var makeNotificationHolder_ = function () {\n//\n// /** Append block with notifications to the document */\n// editor.nodes.notifications = editor.notifications.createHolder();\n//\n// };\n//\n// /**\n// * @private\n// * Append tools passed in editor.tools\n// */\n// var addTools_ = function () {\n//\n// var tool,\n// toolName,\n// toolButton;\n//\n// for ( toolName in editor.settings.tools ) {\n//\n// tool = editor.settings.tools[toolName];\n//\n// editor.tools[toolName] = tool;\n//\n// if (!tool.iconClassname && tool.displayInToolbox) {\n//\n// editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);\n// continue;\n//\n// }\n//\n// if (typeof tool.render != 'function') {\n//\n// editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);\n// continue;\n//\n// }\n//\n// if (!tool.displayInToolbox) {\n//\n// continue;\n//\n// } else {\n//\n// /** if tools is for toolbox */\n// toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);\n//\n// editor.nodes.toolbox.appendChild(toolButton);\n//\n// editor.nodes.toolbarButtons[toolName] = toolButton;\n//\n// }\n//\n// }\n//\n// };\n//\n// var addInlineToolbarTools_ = function () {\n//\n// var tools = {\n//\n// bold: {\n// icon : 'ce-icon-bold',\n// command : 'bold'\n// },\n//\n// italic: {\n// icon : 'ce-icon-italic',\n// command : 'italic'\n// },\n//\n// link: {\n// icon : 'ce-icon-link',\n// command : 'createLink'\n// }\n// };\n//\n// var toolButton,\n// tool;\n//\n// for(var name in tools) {\n//\n// tool = tools[name];\n//\n// toolButton = editor.draw.toolbarButtonInline(name, tool.icon);\n//\n// editor.nodes.inlineToolbar.buttons.appendChild(toolButton);\n// /**\n// * Add callbacks to this buttons\n// */\n// editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);\n//\n// }\n//\n// };\n//\n// /**\n// * @private\n// * Bind editor UI events\n// */\n// var bindEvents_ = function () {\n//\n// editor.core.log('ui.bindEvents fired', 'info');\n//\n// // window.addEventListener('error', function (errorMsg, url, lineNumber) {\n// // editor.notifications.errorThrown(errorMsg, event);\n// // }, false );\n//\n// /** All keydowns on Document */\n// editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n//\n// /** All keydowns on Redactor zone */\n// editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n//\n// /** All keydowns on Document */\n// editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );\n//\n// /**\n// * Mouse click to radactor\n// */\n// editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );\n//\n// /**\n// * Clicks to the Plus button\n// */\n// editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n//\n// /**\n// * Clicks to SETTINGS button in toolbar\n// */\n// editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );\n//\n// /** Bind click listeners on toolbar buttons */\n// for (var button in editor.nodes.toolbarButtons) {\n//\n// editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n//\n// }\n//\n// };\n//\n// ui.addBlockHandlers = function (block) {\n//\n// if (!block) return;\n//\n// /**\n// * Block keydowns\n// */\n// editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n//\n// /**\n// * Pasting content from another source\n// * We have two type of sanitization\n// * First - uses deep-first search algorithm to get sub nodes,\n// * sanitizes whole Block_content and replaces cleared nodes\n// * This method is deprecated\n// * Method is used in editor.callback.blockPaste(event)\n// *\n// * Secont - uses Mutation observer.\n// * Observer \"observe\" DOM changes and send changings to callback.\n// * Callback gets changed node, not whole Block_content.\n// * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n// *\n// * Method is used in editor.callback.blockPasteViaSanitize(event)\n// *\n// * @uses html-janitor\n// * @example editor.callback.blockPasteViaSanitize(event), the second method.\n// *\n// */\n// editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);\n//\n// /**\n// * Show inline toolbar for selected text\n// */\n// editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\n// editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);\n//\n// };\n//\n// /** getting all contenteditable elements */\n// ui.saveInputs = function () {\n//\n// var redactor = editor.nodes.redactor;\n//\n// editor.state.inputs = [];\n//\n// /** Save all inputs in global variable state */\n// var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\n//\n// Array.prototype.map.call(inputs, function (current) {\n//\n// if (!current.type || current.type == 'text' || current.type == 'textarea') {\n//\n// editor.state.inputs.push(current);\n//\n// }\n//\n// });\n//\n// };\n//\n// /**\n// * Adds first initial block on empty redactor\n// */\n// ui.addInitialBlock = function () {\n//\n// var initialBlockType = editor.settings.initialBlockPlugin,\n// initialBlock;\n//\n// if ( !editor.tools[initialBlockType] ) {\n//\n// editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\n// return;\n//\n// }\n//\n// initialBlock = editor.tools[initialBlockType].render();\n//\n// initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);\n//\n// editor.content.insertBlock({\n// type : initialBlockType,\n// block : initialBlock\n// });\n//\n// editor.content.workingNodeChanged(initialBlock);\n//\n// };\n//\n// ui.setInlineToolbarButtonBehaviour = function (button, type) {\n//\n// editor.listeners.add(button, 'mousedown', function (event) {\n//\n// editor.toolbar.inline.toolClicked(event, type);\n//\n// }, false);\n//\n// };\n//\n// return ui;\n//\n// })({});\n\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/ui.js","exports = module.exports = require(\"../../node_modules/css-loader/lib/css-base.js\")(undefined);\n// imports\n\n\n// module\nexports.push([module.id, \":root {\\n\\n /**\\n * Toolbar buttons\\n */\\n\\n}\\n/**\\n* Editor wrapper\\n*/\\n.codex-editor{\\n position: relative;\\n border: 1px solid #ccc;\\n padding: 10px;\\n}\\n.codex-editor .hide {\\n display: none;\\n }\\n\", \"\"]);\n\n// exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/styles/main.css\n// module id = 14\n// module chunks = 0","/*\n\tMIT License http://www.opensource.org/licenses/mit-license.php\n\tAuthor Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\nmodule.exports = function(useSourceMap) {\n\tvar list = [];\n\n\t// return the list of modules as css string\n\tlist.toString = function toString() {\n\t\treturn this.map(function (item) {\n\t\t\tvar content = cssWithMappingToString(item, useSourceMap);\n\t\t\tif(item[2]) {\n\t\t\t\treturn \"@media \" + item[2] + \"{\" + content + \"}\";\n\t\t\t} else {\n\t\t\t\treturn content;\n\t\t\t}\n\t\t}).join(\"\");\n\t};\n\n\t// import a list of modules into the list\n\tlist.i = function(modules, mediaQuery) {\n\t\tif(typeof modules === \"string\")\n\t\t\tmodules = [[null, modules, \"\"]];\n\t\tvar alreadyImportedModules = {};\n\t\tfor(var i = 0; i < this.length; i++) {\n\t\t\tvar id = this[i][0];\n\t\t\tif(typeof id === \"number\")\n\t\t\t\talreadyImportedModules[id] = true;\n\t\t}\n\t\tfor(i = 0; i < modules.length; i++) {\n\t\t\tvar item = modules[i];\n\t\t\t// skip already imported module\n\t\t\t// this implementation is not 100% perfect for weird media query combinations\n\t\t\t// when a module is imported multiple times with different media queries.\n\t\t\t// I hope this will never occur (Hey this way we have smaller bundles)\n\t\t\tif(typeof item[0] !== \"number\" || !alreadyImportedModules[item[0]]) {\n\t\t\t\tif(mediaQuery && !item[2]) {\n\t\t\t\t\titem[2] = mediaQuery;\n\t\t\t\t} else if(mediaQuery) {\n\t\t\t\t\titem[2] = \"(\" + item[2] + \") and (\" + mediaQuery + \")\";\n\t\t\t\t}\n\t\t\t\tlist.push(item);\n\t\t\t}\n\t\t}\n\t};\n\treturn list;\n};\n\nfunction cssWithMappingToString(item, useSourceMap) {\n\tvar content = item[1] || '';\n\tvar cssMapping = item[3];\n\tif (!cssMapping) {\n\t\treturn content;\n\t}\n\n\tif (useSourceMap && typeof btoa === 'function') {\n\t\tvar sourceMapping = toComment(cssMapping);\n\t\tvar sourceURLs = cssMapping.sources.map(function (source) {\n\t\t\treturn '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'\n\t\t});\n\n\t\treturn [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n\t}\n\n\treturn [content].join('\\n');\n}\n\n// Adapted from convert-source-map (MIT)\nfunction toComment(sourceMap) {\n\t// eslint-disable-next-line no-undef\n\tvar base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n\tvar data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;\n\n\treturn '/*# ' + data + ' */';\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./node_modules/css-loader/lib/css-base.js\n// module id = 15\n// module chunks = 0"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///webpack/bootstrap 0c979e981b6898c45a7c","webpack:///./src/components/__module.js","webpack:///./src/components/dom.js","webpack:///./src/components/utils.js","webpack:///./src/components/block.js","webpack:///./src/codex.js","webpack:///./src/components/polyfills.js","webpack:///./src/components/modules nonrecursive [^_](blockManager.js|caret.js|events.js|renderer.js|toolbar.js|toolbox.js|tools.js|ui.js)$","webpack:///./src/components/modules/blockManager.js","webpack:///./src/components/modules/caret.js","webpack:///./src/components/modules/events.js","webpack:///./src/components/modules/renderer.js","webpack:///./src/components/modules/toolbar.js","webpack:///./src/components/modules/toolbox.js","webpack:///./src/components/modules/tools.js","webpack:///./src/components/modules/ui.js","webpack:///./src/styles/main.css","webpack:///./node_modules/css-loader/lib/css-base.js"],"names":["Module","config","new","target","TypeError","Editor","Dom","tagName","classNames","attributes","el","document","createElement","Array","isArray","classList","add","attrName","parent","elements","forEach","appendChild","selector","querySelector","querySelectorAll","node","nodeType","Node","ELEMENT_NODE","Util","msg","type","args","window","console","e","chains","success","fallback","Promise","resolve","reduce","previousValue","currentValue","iteration","then","waitNextBlock","length","chainData","successCallback","fallbackCallback","function","data","catch","collection","prototype","slice","call","object","Object","keys","constructor","Block","tool","_html","compose","wrapper","$","make","CSS","content","html","contentless","emptyText","textContent","trim","emptyMedia","hasMedia","mediaTags","join","state","isEmpty","selected","remove","modules","editorModules","map","module","exports","moduleInstances","configuration","init","start","log","error","constructModules","configureModules","displayName","name","getModulesDiff","diff","moduleName","prepareDecorator","prepare","Tools","UI","items","Renderer","render","BlockManager","holderId","placeholder","sanitizer","p","b","a","hideToolbar","tools","toolsConfig","initialBlock","Element","matches","msMatchesSelector","webkitMatchesSelector","closest","s","documentElement","contains","parentElement","parentNode","_blocks","currentBlockIndex","blocks","Blocks","nodes","redactor","Proxy","set","get","toolName","toolInstance","construct","block","insert","element","index","indexOf","childNode","isElement","parentFirstLevelBlock","currentNode","Error","array","currentBlock","workingArea","push","replace","deleteCount","splice","previousBlock","insertAdjacentElement","nextBlock","targetBlock","newBlock","_","children","instance","isNaN","Number","Caret","lastBlock","Events","subscribers","eventName","callback","previousData","currentHandler","newData","i","insertBlock","sequence","item","Toolbar","actions","plusButton","settingsToggler","removeBlockButton","settings","pluginSettings","defaultSettings","toolbar","append","addEventListener","plusButtonClicked","event","Toolbox","makeRemoveBlockButton","makeBlockSettingsPanel","close","defaultToolbarHeight","defaultOffset","newYCoordinate","offsetTop","style","transform","Math","floor","toolbarOpened","toggle","hide","plusButtonHidden","show","toolbox","buttons","opened","addTools","toolsAvailable","addTool","displayInToolbox","iconClassName","button","toolboxButton","title","dataset","buttonClicked","toolButton","toolClasses","irreplaceable","move","toolboxOpened","open","toolsUnavailable","enableLineBreaks","hasOwnProperty","reject","sequenceData","getListOfPrepareFunctions","toolPreparationList","toolClass","plugin","defaultConfig","available","holder","loadStyles","bindEvents","getElementById","editorWrapper","editorZone","styles","require","tag","toString","head","redactorClicked","clickedNode","setCurrentBlockByChildNode","setToTheLastBlock","isInitialBlock","isInitial","isEmptyBlock"],"mappings":"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AAP,GAAqBnH,OAAOmH,WAA5B,GAA0C,KAApE;AACA,iBAAKnH,MAAL,CAAYoH,KAAZ,GAAoBpH,OAAOoH,KAAP,IAAgB,EAApC;AACA,iBAAKpH,MAAL,CAAYqH,WAAZ,GAA0BrH,OAAOqH,WAAP,IAAsB,EAAhD;AACA,iBAAKrH,MAAL,CAAYmD,IAAZ,GAAmBnD,OAAOmD,IAAP,IAAe,EAAlC;;AAEA;;;AAGA,gBAAI,CAACnD,OAAOsH,YAAZ,EAA0B;;AAEtB,qBAAK,KAAKtH,MAAL,CAAYsH,YAAjB,IAAiC,KAAKtH,MAAL,CAAYoH,KAA7C;AAAoD;AAApD;AAEH,aAJD,MAIO;;AAEH,qBAAKpH,MAAL,CAAYsH,YAAZ,GAA2BtH,OAAOsH,YAAlC;AAEH;AAEJ;;AAED;;;;AAxFJ;AAAA,4BA4FwB;;AAEhB,mBAAO,KAAKtH,MAAZ;AAEH;AAhGL;;AAAA;AAAA;;AA+NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,U;;;;;;;;;AClaA;;;;;AAKA,IAAI,CAACuH,QAAQjE,SAAR,CAAkBkE,OAAvB,EACID,QAAQjE,SAAR,CAAkBkE,OAAlB,GAA4BD,QAAQjE,SAAR,CAAkBmE,iBAAlB,IACxBF,QAAQjE,SAAR,CAAkBo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CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;kBAnRqB2G,Q;;;;;;;;;;;;;;;;;;;;;;;ACRrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmDqB2E,O;;;AAEjB;;;AAGA,yBAAsB;AAAA,QAATrL,MAAS,QAATA,MAAS;;AAAA;;AAAA,kHAEZ,EAACA,cAAD,EAFY;;AAIlB,UAAKqI,KAAL,GAAa;AACTpE,eAAU,IADD;AAETI,eAAU,IAFD;AAGTiH,eAAU,IAHD;;AAKT;AACAC,kBAAa,IANJ;;AAQT;AACAC,uBAAkB,IATT;AAUTC,yBAAmB,IAVV;AAWTC,gBAAU,IAXD;;AAaT;AACAC,sBAAgB,IAdP;AAeTC,uBAAiB;AAfR,KAAb;;AAJkB;AAsBrB;;AAED;;;;;;;;;;;AA8BA;;;2BAGO;AAAA;;AAEH,WAAKvD,KAAL,CAAWpE,OAAX,GAAqBC,EAAEC,IAAF,CAAO,KAAP,EAAckH,QAAQjH,GAAR,CAAYyH,OAA1B,CAArB;;AAEA;;;AAGA,OAAC,SAAD,EAAa,SAAb,EAAwB1K,OAAxB,CAAiC,cAAM;;AAEnC,eAAKkH,KAAL,CAAW5H,EAAX,IAAiByD,EAAEC,IAA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;;;AAIA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA,WAAK3P,MAAL,CAAYiL,OAAZ,CAAoB8C,IAApB;AACA,WAAK/N,MAAL,CAAYiL,OAAZ,CAAoBgD,IAApB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA,WAAKjO,MAAL,CAAYiL,OAAZ,CAAoBE,UAApB,CAA+ByB,IAA/B;;AAEA;;;;;AAKA,UAAIgD,iBAAiB,KAAK5P,MAAL,CAAYmG,KAAZ,CAAkB0J,SAAlB,CAA4B,KAAK7P,MAAL,CAAYwG,YAAZ,CAAyB4C,YAAzB,CAAsC1F,IAAlE,CAArB;AAAA,UACIoM,eAAe,KAAK9P,MAAL,CAAYwG,YAAZ,CAAyB4C,YAAzB,CAAsCxE,OADzD;;AAGA,UAAIgL,kBAAkBE,YAAtB,EAAoC;;AAEhC,aAAK9P,MAAL,CAAYiL,OAAZ,CAAoBE,UAApB,CAA+B2B,IAA/B;AAEH;AAEJ;;;wBA3OS;;AAEN,aAAO;AACHmC,uBAAgB,cADb;AAEHC,oBAAgB;AAFb,OAAP;AAKH;;;;EAzE2BvP,M;;AAiThC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;kBAtgBqByG,E;;;;;;;;ACrDrB;AACA;;;AAGA;AACA,gCAAiC,sLAAsL,4CAA4C,yBAAyB,6BAA6B,oBAAoB,6BAA6B,GAAG,uBAAuB,wBAAwB,OAAO,2BAA2B,gCAAgC,OAAO,eAAe,uBAAuB,YAAY,aAAa,WAAW,eAAe,uBAAuB,mCAAmC,oCAAoC,GAAG,uBAAuB,iBAAiB,0BAA0B,KAAK,wBAAwB,uBAAuB,qBAAqB,yBAAyB,KAAK,qBAAqB,yBAAyB,+BAA+B,4BAA4B,gCAAgC,kBAAkB,mBAAmB,wBAAwB,yBAAyB,6BAA6B,4BAA4B,mBAAmB,sBAAsB,qBAAqB,uBAAuB,yBAAyB,KAAK,6BAA6B,sBAAsB,KAAK,eAAe,yBAAyB,qCAAqC,2BAA2B,GAAG,uBAAuB,qBAAqB,8BAA8B,OAAO,uBAAuB,gCAAgC,2BAA2B,oBAAoB,8BAA8B,sBAAsB,uBAAuB,8BAA8B,2BAA2B,6BAA6B,kCAAkC,+BAA+B,2BAA2B,sBAAsB,uBAAuB,0BAA0B,wDAAwD,wDAAwD,wCAAwC,2BAA2B,uBAAuB,4BAA4B,KAAK,aAAa,4BAA4B,kBAAkB,GAAG,uBAAuB,gCAAgC,KAAK,sBAAsB,uBAAuB,qBAAqB,KAAK;;AAE7xE;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,mCAAmC,gBAAgB;AACnD,IAAI;AACJ;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,gBAAgB,iBAAiB;AACjC;AACA;AACA;AACA;AACA,YAAY,oBAAoB;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,oDAAoD,cAAc;;AAElE;AACA","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 \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\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.l = 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// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 4);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 0c979e981b6898c45a7c","/**\n * @abstract\n * @class Module\n * @classdesc All modules inherits from this class.\n *\n * @typedef {Module} Module\n * @property {Object} config - Editor user settings\n * @property {Object} Editor - List of Editor modules\n */\nexport default class Module {\n\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor({ config } = {}) {\n\n if (new.target === Module) {\n\n throw new TypeError('Constructors for abstract class Module are not allowed.');\n\n }\n\n /**\n * @type {EditorConfig}\n */\n this.config = config;\n\n /**\n * @type {EditorComponents}\n */\n this.Editor = null;\n\n }\n\n /**\n * Editor modules setter\n *\n * @param Editor\n * @param Editor.modules {@link CodexEditor#moduleInstances}\n * @param Editor.config {@link CodexEditor#configuration}\n */\n set state(Editor) {\n\n this.Editor = Editor;\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/__module.js","/**\n * DOM manupulations helper\n */\nexport default class Dom {\n\n /**\n * Helper for making Elements with classname and attributes\n *\n * @param {string} tagName - new Element tag name\n * @param {array|string} classNames - list or name of CSS classname(s)\n * @param {Object} attributes - any attributes\n * @return {Element}\n */\n static make(tagName, classNames = null, attributes = {}) {\n\n var el = document.createElement(tagName);\n\n if ( Array.isArray(classNames) ) {\n\n el.classList.add(...classNames);\n\n } else if( classNames ) {\n\n el.classList.add(classNames);\n\n }\n\n for (let attrName in attributes) {\n\n el[attrName] = attributes[attrName];\n\n }\n\n return el;\n\n }\n\n /**\n * Append one or several elements to the parent\n *\n * @param {Element} parent - where to append\n * @param {Element|Element[]} - element ore elements list\n */\n static append(parent, elements) {\n\n if ( Array.isArray(elements) ) {\n\n elements.forEach( el => parent.appendChild(el) );\n\n } else {\n\n parent.appendChild(elements);\n\n }\n\n }\n\n /**\n * Selector Decorator\n *\n * Returns first match\n *\n * @param {Element} el - element we searching inside. Default - DOM Document\n * @param {String} selector - searching string\n *\n * @returns {Element}\n */\n static find(el = document, selector) {\n\n return el.querySelector(selector);\n\n }\n\n /**\n * Selector Decorator.\n *\n * Returns all matches\n *\n * @param {Element} el - element we searching inside. Default - DOM Document\n * @param {String} selector - searching string\n * @returns {NodeList}\n */\n static findAll(el = document, selector) {\n\n return el.querySelectorAll(selector);\n\n }\n\n /**\n * Check if object is DOM node\n *\n * @param {Object} node\n * @returns {boolean}\n */\n static isElement(node) {\n\n return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE;\n\n }\n\n};\n\n\n// WEBPACK FOOTER //\n// ./src/components/dom.js","/**\n * Codex Editor Util\n */\nexport default class Util {\n\n /**\n * Custom logger\n *\n * @param {string} msg - message\n * @param {string} type - logging type 'log'|'warn'|'error'|'info'\n * @param {*} args - argument to log with a message\n */\n static log(msg, type, args) {\n\n type = type || 'log';\n\n if (!args) {\n\n args = 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 ( args ) window.console[ type ]( msg, args );\n else window.console[ type ]( msg );\n\n }\n\n } catch(e) {\n // do nothing\n }\n\n }\n\n /**\n * @typedef {Object} ChainData\n * @property {Object} data - data that will be passed to the success or fallback\n * @property {Function} function - function's that must be called asynchronically\n */\n\n /**\n * Fires a promise sequence asyncronically\n *\n * @param {Object[]} chains - list or ChainData's\n * @param {Function} success - success callback\n * @param {Function} fallback - callback that fires in case of errors\n *\n * @return {Promise}\n */\n static sequence(chains, success = () => {}, fallback = () => {}) {\n\n return new Promise(function (resolve) {\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 chains.reduce(function (previousValue, currentValue, iteration) {\n\n return previousValue\n .then(() => waitNextBlock(currentValue, success, fallback))\n .then(() => {\n\n // finished\n if (iteration === chains.length - 1) {\n\n resolve();\n\n }\n\n });\n\n }, Promise.resolve());\n\n });\n\n /**\n * Decorator\n *\n * @param {ChainData} chainData\n *\n * @param {Function} successCallback\n * @param {Function} fallbackCallback\n *\n * @return {Promise}\n */\n function waitNextBlock(chainData, successCallback, fallbackCallback) {\n\n return new Promise(function (resolve) {\n\n chainData.function()\n .then(() => {\n\n successCallback(chainData.data);\n\n })\n .then(resolve)\n .catch(function () {\n\n fallbackCallback(chainData.data);\n\n // anyway, go ahead even it falls\n resolve();\n\n });\n\n });\n\n }\n\n }\n\n /**\n * Make array from array-like collection\n *\n * @param {*} collection\n *\n * @return {Array}\n */\n static array(collection) {\n\n return Array.prototype.slice.call(collection);\n\n }\n\n /**\n * Checks if object is empty\n *\n * @param {Object} object\n * @return {boolean}\n */\n static isEmpty(object) {\n\n return Object.keys(object).length === 0 && object.constructor === Object;\n\n }\n\n};\n\n\n// WEBPACK FOOTER //\n// ./src/components/utils.js","/**\n *\n * @class Block\n * @classdesc This class describes editor`s block, including block`s HTMLElement, data and tool\n *\n * @property {Tool} tool — current block tool (Paragraph, for example)\n * @property {Object} CSS — block`s css classes\n *\n */\n\n\nexport default class Block {\n\n /**\n * @constructor\n *\n * @param {Object} tool — current block plugin`s instance\n */\n constructor(tool) {\n\n this.tool = tool;\n\n this._html = this.compose();\n\n }\n\n /**\n * CSS classes for the Block\n * @return {{wrapper: string, content: string}}\n */\n static get CSS() {\n\n return {\n wrapper: 'ce-block',\n content: 'ce-block__content',\n selected: 'ce-block--selected'\n };\n\n }\n\n /**\n * Make default block wrappers and put tool`s content there\n *\n * @returns {HTMLDivElement}\n * @private\n */\n compose() {\n\n let wrapper = $.make('div', Block.CSS.wrapper),\n content = $.make('div', Block.CSS.content);\n\n content.appendChild(this.tool.html);\n wrapper.appendChild(content);\n\n return wrapper;\n\n }\n\n /**\n * Get block`s HTML\n *\n * @returns {HTMLDivElement}\n */\n get html() {\n\n return this._html;\n\n }\n\n /**\n * Check block for emptiness\n *\n * @return {Boolean}\n */\n get isEmpty() {\n\n /**\n * Allow Tool to represent decorative contentless blocks: for example \"* * *\"-tool\n * That Tools are not empty\n */\n if (this.tool.contentless) {\n\n return false;\n\n }\n\n let emptyText = this._html.textContent.trim().length === 0,\n emptyMedia = !this.hasMedia;\n\n return emptyText && emptyMedia;\n\n }\n\n /**\n * Check if block has a media content such as images, iframes and other\n * @return {Boolean}\n */\n get hasMedia() {\n\n /**\n * This tags represents media-content\n * @type {string[]}\n */\n const mediaTags = [\n 'img',\n 'iframe',\n 'video',\n 'audio',\n 'source',\n 'input',\n 'textarea',\n 'twitterwidget'\n ];\n\n return !!this._html.querySelector(mediaTags.join(','));\n\n }\n\n /**\n * Set selected state\n * @param {Boolean} state - 'true' to select, 'false' to remove selection\n */\n set selected(state) {\n\n /**\n * We don't need to mark Block as Selected when it is not empty\n */\n if (state === true && !this.isEmpty) {\n\n this._html.classList.add(Block.CSS.selected);\n\n } else {\n\n this._html.classList.remove(Block.CSS.selected);\n\n }\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/block.js","/**\n * Codex Editor\n *\n * Short Description (눈_눈;)\n * @version 2.0.0\n *\n * How to start?\n * Example:\n * new CodexEditor({\n * holderId : 'codex-editor',\n * initialBlock : 'paragraph',\n * placeholder : 'Write your story....',\n * tools: {\n * quote: Quote,\n * anotherTool : AnotherTool\n * },\n * toolsConfig: {\n * quote: {\n * iconClassname : 'quote-icon',\n * displayInToolbox : true,\n * enableLineBreaks : true\n * },\n * anotherTool: {\n * iconClassname : 'tool-icon'\n * }\n * }\n * });\n *\n * - tools is an object: {\n * pluginName: PluginClass,\n * .....\n * }\n * - toolsConfig is an additional configuration that uses Codex Editor API\n * iconClassname - CSS classname of toolbox icon\n * displayInToolbox - if you want to see your Tool in toolbox hided in \"plus\" button, than set \"True\". By default : \"False\"\n * enableLineBreaks - by default enter creates new block that set as initialblock, but if you set this property \"True\", enter will break the lines in current block\n *\n * @author CodeX-Team \n *\n */\n\n/**\n * @typedef {CodexEditor} CodexEditor - editor class\n */\n\n/**\n * @typedef {Object} EditorConfig\n * @property {String} holderId - Element to append Editor\n * @property {Array} data - Blocks list in JSON-format\n * @property {Object} tools - Map for used Tools in format { name : Class, ... }\n * @property {String} initialBlock - This Tool will be added by default\n * @property {String} placeholder - First Block placeholder\n * @property {Object} sanitizer - @todo fill desc\n * @property {Boolean} hideToolbar - @todo fill desc\n * @property {Object} toolsConfig - tools configuration {@link Tools#ToolsConfig}\n */\n\n/**\n * Dynamically imported utils\n *\n * @typedef {Dom} $ - {@link components/dom.js}\n * @typedef {Util} _ - {@link components/utils.js}\n */\n\n'use strict';\n\n/**\n * Apply polyfills\n */\nimport 'components/polyfills';\n\n/**\n * Require Editor modules places in components/modules dir\n */\n// eslint-disable-next-line\nlet modules = editorModules.map( module => require('./components/modules/' + module ));\n\n/**\n * @class\n *\n * @classdesc CodeX Editor base class\n *\n * @property this.config - all settings\n * @property this.moduleInstances - constructed editor components\n *\n * @type {CodexEditor}\n */\nmodule.exports = class CodexEditor {\n\n /** Editor version */\n static get version() {\n\n return VERSION;\n\n }\n\n /**\n * @param {EditorConfig} config - user configuration\n *\n */\n constructor(config) {\n\n /**\n * Configuration object\n * @type {EditorConfig}\n */\n this.config = {};\n\n /**\n * @typedef {Object} EditorComponents\n * @property {BlockManager} BlockManager\n * @property {Tools} Tools\n * @property {Events} Events\n * @property {UI} UI\n * @property {Toolbar} Toolbar\n * @property {Toolbox} Toolbox\n * @property {Renderer} Renderer\n */\n this.moduleInstances = {};\n\n Promise.resolve()\n .then(() => {\n\n this.configuration = config;\n\n })\n .then(() => this.init())\n .then(() => this.start())\n .then(() => {\n\n console.log('CodeX Editor is ready');\n\n })\n .catch(error => {\n\n console.log('CodeX Editor does not ready because of %o', error);\n\n });\n\n }\n\n /**\n * Setting for configuration\n * @param {EditorConfig} config\n */\n set configuration(config) {\n\n this.config.holderId = config.holderId;\n this.config.placeholder = config.placeholder || 'write your story...';\n this.config.sanitizer = config.sanitizer || {\n p: true,\n b: true,\n a: true\n };\n\n this.config.hideToolbar = config.hideToolbar ? config.hideToolbar : false;\n this.config.tools = config.tools || {};\n this.config.toolsConfig = config.toolsConfig || {};\n this.config.data = config.data || [];\n\n /**\n * If initial Block's Tool was not passed, use the first Tool in config.tools\n */\n if (!config.initialBlock) {\n\n for (this.config.initialBlock in this.config.tools) break;\n\n } else {\n\n this.config.initialBlock = config.initialBlock;\n\n }\n\n }\n\n /**\n * Returns private property\n * @returns {EditorConfig}\n */\n get configuration() {\n\n return this.config;\n\n }\n\n /**\n * Initializes modules:\n * - make and save instances\n * - configure\n */\n init() {\n\n /**\n * Make modules instances and save it to the @property this.moduleInstances\n */\n this.constructModules();\n\n /**\n * Modules configuration\n */\n this.configureModules();\n\n }\n\n /**\n * Make modules instances and save it to the @property this.moduleInstances\n */\n constructModules() {\n\n modules.forEach( Module => {\n\n try {\n\n /**\n * We use class name provided by displayName property\n *\n * On build, Babel will transform all Classes to the Functions so, name will always be 'Function'\n * To prevent this, we use 'babel-plugin-class-display-name' plugin\n * @see https://www.npmjs.com/package/babel-plugin-class-display-name\n */\n this.moduleInstances[Module.displayName] = new Module({\n config : this.configuration\n });\n\n } catch ( e ) {\n\n console.log('Module %o skipped because %o', Module, e);\n\n }\n\n });\n\n }\n\n /**\n * Modules instances configuration:\n * - pass other modules to the 'state' property\n * - ...\n */\n configureModules() {\n\n for(let name in this.moduleInstances) {\n\n /**\n * Module does not need self-instance\n */\n this.moduleInstances[name].state = this.getModulesDiff( name );\n\n }\n\n }\n\n /**\n * Return modules without passed name\n */\n getModulesDiff( name ) {\n\n let diff = {};\n\n for(let moduleName in this.moduleInstances) {\n\n /**\n * Skip module with passed name\n */\n if (moduleName === name) {\n\n continue;\n\n }\n diff[moduleName] = this.moduleInstances[moduleName];\n\n }\n\n return diff;\n\n }\n\n /**\n * Start Editor!\n *\n * @return {Promise}\n */\n start() {\n\n let prepareDecorator = module => module.prepare();\n\n return Promise.resolve()\n .then(prepareDecorator(this.moduleInstances.Tools))\n .then(prepareDecorator(this.moduleInstances.UI))\n .then(() => {\n\n if (this.config.data && this.config.data.items) {\n\n this.moduleInstances.Renderer.render(this.config.data.items);\n\n }\n\n })\n .then(prepareDecorator(this.moduleInstances.BlockManager))\n\n .catch(function (error) {\n\n console.log('Error occured', error);\n\n });\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 : ['text', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'],\n// holderId : 'codex-editor',\n//\n// // Type of block showing on empty editor\n// initialBlockPlugin: 'text'\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// 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// ./src/codex.js","/**\n * Element.closest()\n *\n * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest\n */\nif (!Element.prototype.matches)\n Element.prototype.matches = Element.prototype.msMatchesSelector ||\n Element.prototype.webkitMatchesSelector;\n\nif (!Element.prototype.closest)\n Element.prototype.closest = function (s) {\n\n var el = this;\n\n if (!document.documentElement.contains(el)) return null;\n do {\n\n if (el.matches(s)) return el;\n el = el.parentElement || el.parentNode;\n\n } while (el !== null);\n return null;\n\n };\n\n\n\n// WEBPACK FOOTER //\n// ./src/components/polyfills.js","var map = {\n\t\"./blockManager.js\": 7,\n\t\"./caret.js\": 8,\n\t\"./events.js\": 9,\n\t\"./renderer.js\": 10,\n\t\"./toolbar.js\": 11,\n\t\"./toolbox.js\": 12,\n\t\"./tools.js\": 13,\n\t\"./ui.js\": 14\n};\nfunction webpackContext(req) {\n\treturn __webpack_require__(webpackContextResolve(req));\n};\nfunction webpackContextResolve(req) {\n\tvar id = map[req];\n\tif(!(id + 1)) // check for number or string\n\t\tthrow new Error(\"Cannot find module '\" + req + \"'.\");\n\treturn id;\n};\nwebpackContext.keys = function webpackContextKeys() {\n\treturn Object.keys(map);\n};\nwebpackContext.resolve = webpackContextResolve;\nmodule.exports = webpackContext;\nwebpackContext.id = 6;\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/components/modules nonrecursive [^_](blockManager.js|caret.js|events.js|renderer.js|toolbar.js|toolbox.js|tools.js|ui.js)$\n// module id = 6\n// module chunks = 0","/**\n * @class BlockManager\n * @classdesc Manage editor`s blocks storage and appearance\n *\n * @module BlockManager\n */\n\nimport Block from '../block';\n\n/**\n * @typedef {BlockManager} BlockManager\n * @property {Number} currentBlockIndex - Index of current working block\n * @property {Proxy} _blocks - Proxy for Blocks instance {@link Blocks}\n */\nexport default class BlockManager extends Module {\n\n /**\n * @constructor\n * @param {EditorConfig} config\n */\n constructor({config}) {\n\n super({config});\n\n /**\n * Proxy for Blocks instance {@link Blocks}\n *\n * @type {Proxy}\n * @private\n */\n this._blocks = null;\n\n /**\n * Index of current working block\n *\n * @type {number}\n * @private\n */\n this.currentBlockIndex = -1;\n\n }\n\n /**\n * Should be called after Editor.UI preparation\n * Define this._blocks property\n *\n * @returns {Promise}\n */\n prepare() {\n\n return new Promise(resolve => {\n\n let blocks = new Blocks(this.Editor.UI.nodes.redactor);\n\n /**\n * We need to use Proxy to overload set/get [] operator.\n * So we can use array-like syntax to access blocks\n *\n * @example\n * this._blocks[0] = new Block(...);\n *\n * block = this._blocks[0];\n *\n * @todo proxy the enumerate method\n *\n * @type {Proxy}\n * @private\n */\n this._blocks = new Proxy(blocks, {\n set: Blocks.set,\n get: Blocks.get\n });\n\n resolve();\n\n });\n\n }\n\n /**\n * Insert new block into _blocks\n *\n * @param {String} toolName — plugin name\n * @param {Object} data — plugin data\n */\n insert(toolName, data = {}) {\n\n let toolInstance = this.Editor.Tools.construct(toolName, data),\n block = new Block(toolInstance);\n\n this._blocks[++this.currentBlockIndex] = block;\n\n /**\n * @todo fire Tool's appendCallback\n */\n\n }\n\n /**\n * Replace current working block\n *\n * @param {String} toolName — plugin name\n * @param {Object} data — plugin data\n */\n replace(toolName, data = {}) {\n\n let toolInstance = this.Editor.Tools.construct(toolName, data),\n block = new Block(toolInstance);\n\n this._blocks.insert(this.currentBlockIndex, block, true);\n\n /**\n * @todo fire Tool's appendCallback\n */\n\n }\n\n /**\n * Get Block instance by html element\n *\n * @todo get first level block before searching\n *\n * @param {HTMLElement} element\n * @returns {Block}\n */\n getBlock(element) {\n\n let nodes = this._blocks.nodes,\n index = nodes.indexOf(element);\n\n if (index >= 0) {\n\n return this._blocks[index];\n\n }\n\n }\n\n /**\n * Get current Block instance\n *\n * @return {Block}\n */\n get currentBlock() {\n\n return this._blocks[this.currentBlockIndex];\n\n }\n\n /**\n * Get working html element\n *\n * @return {HTMLElement}\n */\n get currentNode() {\n\n return this._blocks.nodes[this.currentBlockIndex];\n\n }\n\n /**\n * Set currentBlockIndex to passed block\n *\n * @todo get first level block before searching\n *\n * @param {HTMLElement} element\n */\n set currentNode(element) {\n\n let nodes = this._blocks.nodes;\n\n /**\n * Update current Block's index\n * @type {number}\n */\n this.currentBlockIndex = nodes.indexOf(element);\n\n /**\n * Remove previous selected Block's state\n */\n this._blocks.array.forEach( block => block.selected = false);\n\n /**\n * Mark current Block as selected\n * @type {boolean}\n */\n this.currentBlock.selected = true;\n\n }\n\n /**\n * Get array of Block instances\n *\n * @returns {Block[]} {@link Blocks#array}\n */\n get blocks() {\n\n return this._blocks.array;\n\n }\n\n /**\n * 1) Find first-level Block from passed child Node\n * 2) Mark it as current\n *\n * @param {Element|Text} childNode - look ahead from this node.\n * @throws Error - when passed Node is not included at the Block\n */\n setCurrentBlockByChildNode(childNode) {\n\n /**\n * If node is Text TextNode\n */\n if (!$.isElement(childNode)) {\n\n childNode = childNode.parentNode;\n\n }\n\n let parentFirstLevelBlock = childNode.closest(`.${Block.CSS.wrapper}`);\n\n if (parentFirstLevelBlock) {\n\n this.currentNode = parentFirstLevelBlock;\n\n } else {\n\n throw new Error('Can not find a Block from this child Node');\n\n }\n\n }\n\n}\n\n/**\n * @class Blocks\n * @classdesc Class to work with Block instances array\n *\n * @private\n *\n * @property {HTMLElement} workingArea — editor`s working node\n *\n */\nclass Blocks {\n\n /**\n * @constructor\n *\n * @param {HTMLElement} workingArea — editor`s working node\n */\n constructor(workingArea) {\n\n this.blocks = [];\n this.workingArea = workingArea;\n\n }\n\n /**\n * Push back new Block\n *\n * @param {Block} block\n */\n push(block) {\n\n this.blocks.push(block);\n this.workingArea.appendChild(block.html);\n\n }\n\n /**\n * Insert new Block at passed index\n *\n * @param {Number} index — index to insert Block\n * @param {Block} block — Block to insert\n * @param {Boolean} replace — it true, replace block on given index\n */\n insert(index, block, replace = false) {\n\n if (!this.length) {\n\n this.push(block);\n return;\n\n }\n\n if (index > this.length) {\n\n index = this.length;\n\n }\n\n if (replace) {\n\n this.blocks[index].html.remove();\n\n }\n\n let deleteCount = replace ? 1 : 0;\n\n this.blocks.splice(index, deleteCount, block);\n\n if (index > 0) {\n\n let previousBlock = this.blocks[index - 1];\n\n previousBlock.html.insertAdjacentElement('afterend', block.html);\n\n } else {\n\n let nextBlock = this.blocks[index + 1];\n\n if (nextBlock) {\n\n nextBlock.html.insertAdjacentElement('beforebegin', block.html);\n\n } else {\n\n this.workingArea.appendChild(block.html);\n\n }\n\n }\n\n }\n\n /**\n * Insert Block after passed target\n *\n * @todo decide if this method is necessary\n *\n * @param {Block} targetBlock — target after wich Block should be inserted\n * @param {Block} newBlock — Block to insert\n */\n insertAfter(targetBlock, newBlock) {\n\n let index = this.blocks.indexOf(targetBlock);\n\n this.insert(index + 1, newBlock);\n\n }\n\n /**\n * Get Block by index\n *\n * @param {Number} index — Block index\n * @returns {Block}\n */\n get(index) {\n\n return this.blocks[index];\n\n }\n\n /**\n * Return index of passed Block\n *\n * @param {Block} block\n * @returns {Number}\n */\n indexOf(block) {\n\n return this.blocks.indexOf(block);\n\n }\n\n /**\n * Get length of Block instances array\n *\n * @returns {Number}\n */\n get length() {\n\n return this.blocks.length;\n\n }\n\n /**\n * Get Block instances array\n *\n * @returns {Block[]}\n */\n get array() {\n\n return this.blocks;\n\n }\n\n /**\n * Get blocks html elements array\n *\n * @returns {HTMLElement[]}\n */\n get nodes() {\n\n return _.array(this.workingArea.children);\n\n }\n\n /**\n * Proxy trap to implement array-like setter\n *\n * @example\n * blocks[0] = new Block(...)\n *\n * @param {Blocks} instance — Blocks instance\n * @param {Number|String} index — block index\n * @param {Block} block — Block to set\n * @returns {Boolean}\n */\n static set(instance, index, block) {\n\n if (isNaN(Number(index))) {\n\n return false;\n\n }\n\n instance.insert(index, block);\n\n return true;\n\n }\n\n /**\n * Proxy trap to implement array-like getter\n *\n * @param {Blocks} instance — Blocks instance\n * @param {Number|String} index — Block index\n * @returns {Block|*}\n */\n static get(instance, index) {\n\n if (isNaN(Number(index))) {\n\n return instance[index];\n\n }\n\n return instance.get(index);\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/blockManager.js","/**\n * @class Caret\n * @classdesc Contains methods for working Caret\n *\n * @typedef {Caret} Caret\n */\nexport default class Caret extends Module {\n\n /**\n * @constructor\n */\n constructor({config}) {\n\n super({config});\n\n }\n\n /**\n * Set Caret to the last Block\n *\n * If last block is not empty, append another empty block\n */\n setToTheLastBlock() {\n\n let blocks = this.Editor.BlockManager.blocks,\n lastBlock;\n\n if (blocks.length) {\n\n lastBlock = blocks[blocks.length - 1];\n\n }\n\n /**\n * If last block is empty and it is an initialBlock, set to that.\n * Otherwise, append new empty block and set to that\n */\n if (lastBlock.isEmpty) {\n\n this.set(lastBlock.html);\n\n } else {\n\n this.Editor.BlockManager.insert(this.config.initialBlock);\n\n }\n\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 }\n\n /**\n * Set caret to the passed Node\n * @param {Element} node - content-editable Element\n */\n set(node) {\n\n /**\n * @todo add working with Selection\n * tmp: work with textContent\n */\n\n node.textContent += '|';\n\n }\n\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/caret.js","/**\n * @module eventDispatcher\n *\n * Has two important methods:\n * - {Function} on - appends subscriber to the event. If event doesn't exist - creates new one\n * - {Function} emit - fires all subscribers with data\n *\n * @version 1.0.0\n *\n * @typedef {Events} Events\n * @property {Object} subscribers - all subscribers grouped by event name\n */\nexport default class Events extends Module {\n\n /**\n * @constructor\n */\n constructor({config}) {\n\n super({config});\n this.subscribers = {};\n\n }\n\n /**\n * @param {String} eventName - event name\n * @param {Function} callback - subscriber\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 /**\n * @param {String} eventName - event name\n * @param {Object} data - subscribers get this data when they were fired\n */\n emit(eventName, data) {\n\n this.subscribers[eventName].reduce(function (previousData, currentHandler) {\n\n let newData = currentHandler(previousData);\n\n return newData ? newData : previousData;\n\n }, data);\n\n }\n\n /**\n * Destroyer\n * clears subsribers list\n */\n destroy() {\n\n this.subscribers = null;\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/events.js","/**\n * Codex Editor Renderer Module\n *\n * @module Renderer\n * @author CodeX Team\n *\n * @version 2.0.0\n */\nexport default class Renderer extends Module {\n\n /**\n * @constructor\n * @param {EditorConfig} config\n */\n constructor({config}) {\n\n super({config});\n\n }\n\n /**\n * @typedef {Object} RendererItems\n * @property {String} type - tool name\n * @property {Object} data - tool data\n */\n\n /**\n * @example\n *\n * items: [\n * {\n * type : 'paragraph',\n * data : {\n * text : 'Hello from Codex!'\n * }\n * },\n * {\n * type : 'paragraph',\n * data : {\n * text : 'Leave feedback if you like it!'\n * }\n * },\n * ]\n *\n */\n\n /**\n * Make plugin blocks from array of plugin`s data\n * @param {RendererItems[]} items\n */\n render(items) {\n\n let chainData = [];\n\n for (let i = 0; i < items.length; i++) {\n\n chainData.push({\n function: () => this.insertBlock(items[i])\n });\n\n }\n\n _.sequence(chainData);\n\n }\n\n /**\n * Get plugin instance\n * Add plugin instance to BlockManager\n * Insert block to working zone\n *\n * @param {Object} item\n * @returns {Promise.}\n * @private\n */\n insertBlock(item) {\n\n let tool = item.type,\n data = item.data;\n\n this.Editor.BlockManager.insert(tool, data);\n\n return Promise.resolve();\n\n }\n\n}\n\n// module.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 Promise -> 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// ./src/components/modules/renderer.js","/**\n *\n * «Toolbar» is the node that moves up/down over current block\n *\n * ______________________________________ Toolbar ____________________________________________\n * | |\n * | ..................... Content .................... ......... Block Actions .......... |\n * | . . . . |\n * | . . . [Open Settings] [Remove Block] . |\n * | . [Plus Button] [Toolbox: {Tool1}, {Tool2}] . . . |\n * | . . . [Settings Panel] . |\n * | .................................................. .................................. |\n * | |\n * |___________________________________________________________________________________________|\n *\n *\n * Toolbox — its an Element contains tools buttons. Can be shown by Plus Button.\n *\n * _______________ Toolbox _______________\n * | |\n * | [Header] [Image] [List] [Quote] ... |\n * |_______________________________________|\n *\n *\n * Settings Panel — is an Element with block settings:\n *\n * ____ Settings Panel ____\n * | ...................... |\n * | . Tool Settings . |\n * | ...................... |\n * | . Default Settings . |\n * | ...................... |\n * |________________________|\n *\n *\n * @class\n * @classdesc Toolbar module\n *\n * @typedef {Toolbar} Toolbar\n * @property {Object} nodes\n * @property {Element} nodes.wrapper - Toolbar main element\n * @property {Element} nodes.content - Zone with Plus button and toolbox.\n * @property {Element} nodes.actions - Zone with Block Settings and Remove Button\n * @property {Element} nodes.plusButton - Button that opens or closes Toolbox\n * @property {Element} nodes.toolbox - Container for tools\n * @property {Element} nodes.settingsToggler - open/close Settings Panel button\n * @property {Element} nodes.removeBlockButton - Remove Block button\n * @property {Element} nodes.settings - Settings Panel\n * @property {Element} nodes.pluginSettings - Plugin Settings section of Settings Panel\n * @property {Element} nodes.defaultSettings - Default Settings section of Settings Panel\n */\nexport default class Toolbar extends Module {\n\n /**\n * @constructor\n */\n constructor({config}) {\n\n super({config});\n\n this.nodes = {\n wrapper : null,\n content : null,\n actions : null,\n\n // Content Zone\n plusButton : null,\n\n // Actions Zone\n settingsToggler : null,\n removeBlockButton: null,\n settings: null,\n\n // Settings Zone: Plugin Settings and Default Settings\n pluginSettings: null,\n defaultSettings: null,\n };\n\n }\n\n /**\n * CSS styles\n * @return {Object}\n * @constructor\n */\n static get CSS() {\n\n return {\n toolbar: 'ce-toolbar',\n content: 'ce-toolbar__content',\n actions: 'ce-toolbar__actions',\n\n toolbarOpened: 'ce-toolbar--opened',\n\n // Content Zone\n plusButton: 'ce-toolbar__plus',\n plusButtonHidden: 'ce-toolbar__plus--hidden',\n\n // Actions Zone\n settingsToggler: 'ce-toolbar__settings-btn',\n removeBlockButton: 'ce-toolbar__remove-btn',\n\n // Settings Panel\n settings: 'ce-settings',\n defaultSettings: 'ce-settings_default',\n pluginSettings: 'ce-settings_plugin',\n };\n\n }\n\n /**\n * Makes toolbar\n */\n make() {\n\n this.nodes.wrapper = $.make('div', Toolbar.CSS.toolbar);\n\n /**\n * Make Content Zone and Actions Zone\n */\n ['content', 'actions'].forEach( el => {\n\n this.nodes[el] = $.make('div', Toolbar.CSS[el]);\n $.append(this.nodes.wrapper, this.nodes[el]);\n\n });\n\n\n /**\n * Fill Content Zone:\n * - Plus Button\n * - Toolbox\n */\n this.nodes.plusButton = $.make('div', Toolbar.CSS.plusButton);\n $.append(this.nodes.content, this.nodes.plusButton);\n this.nodes.plusButton.addEventListener('click', event => this.plusButtonClicked(event), false);\n\n\n /**\n * Make a Toolbox\n */\n this.Editor.Toolbox.make();\n\n /**\n * Fill Actions Zone:\n * - Settings Toggler\n * - Remove Block Button\n * - Settings Panel\n */\n this.nodes.settingsToggler = $.make('span', Toolbar.CSS.settingsToggler);\n this.nodes.removeBlockButton = this.makeRemoveBlockButton();\n\n $.append(this.nodes.actions, [this.nodes.settingsToggler, this.nodes.removeBlockButton]);\n\n /**\n * Make and append Settings Panel\n */\n this.makeBlockSettingsPanel();\n\n /**\n * Append toolbar to the Editor\n */\n $.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);\n\n }\n\n /**\n * Panel with block settings with 2 sections:\n *\n * @return {Element}\n */\n makeBlockSettingsPanel() {\n\n this.nodes.settings = $.make('div', Toolbar.CSS.settings);\n\n this.nodes.pluginSettings = $.make('div', Toolbar.CSS.pluginSettings);\n this.nodes.defaultSettings = $.make('div', Toolbar.CSS.defaultSettings);\n\n $.append(this.nodes.settings, [this.nodes.pluginSettings, this.nodes.defaultSettings]);\n $.append(this.nodes.actions, this.nodes.settings);\n\n }\n\n /**\n * Makes Remove Block button, and confirmation panel\n * @return {Element} wrapper with button and panel\n */\n makeRemoveBlockButton() {\n\n /**\n * @todo add confirmation panel and handlers\n * @see {@link settings#makeRemoveBlockButton}\n */\n return $.make('span', Toolbar.CSS.removeBlockButton);\n\n }\n\n /**\n * Move Toolbar to the Current Block\n */\n move() {\n\n /** Close Toolbox when we move toolbar */\n this.Editor.Toolbox.close();\n\n let currentNode = this.Editor.BlockManager.currentNode;\n\n /**\n * If no one Block selected as a Current\n */\n if (!currentNode) {\n\n return;\n\n }\n\n /**\n * @todo Compute dynamically on prepare\n * @type {number}\n */\n const defaultToolbarHeight = 49;\n const defaultOffset = 34;\n\n var newYCoordinate = currentNode.offsetTop - (defaultToolbarHeight / 2) + defaultOffset;\n\n this.nodes.wrapper.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`;\n\n /** Close trash actions */\n // editor.toolbar.settings.hideRemoveActions();\n\n }\n\n /**\n * Open Toolbar with Plus Button\n */\n open() {\n\n this.nodes.wrapper.classList.add(Toolbar.CSS.toolbarOpened);\n\n }\n\n /**\n * Close the Toolbar\n */\n close() {\n\n this.nodes.wrapper.classList.remove(Toolbar.CSS.toolbarOpened);\n\n }\n\n /**\n * Plus Button public methods\n * @return {{hide: function(): void, show: function(): void}}\n */\n get plusButton() {\n\n return {\n hide: () => this.nodes.plusButton.classList.add(Toolbar.CSS.plusButtonHidden),\n show: () => this.nodes.plusButton.classList.remove(Toolbar.CSS.plusButtonHidden)\n };\n\n }\n\n /**\n * Handler for Plus Button\n * @param {MouseEvent} event\n */\n plusButtonClicked(event) {\n\n this.Editor.Toolbox.toggle();\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/toolbar.js","/**\n * @class Toolbox\n * @classdesc Holder for Tools\n *\n * @typedef {Toolbox} Toolbox\n * @property {Boolean} opened - opening state\n * @property {Object} nodes - Toolbox nodes\n * @property {Object} CSS - CSS class names\n *\n */\nexport default class Toolbox extends Module {\n\n /**\n * @constructor\n */\n constructor({config}) {\n\n super({config});\n\n this.nodes = {\n toolbox: null,\n buttons: []\n };\n\n /**\n * Opening state\n * @type {boolean}\n */\n this.opened = false;\n\n }\n\n /**\n * CSS styles\n * @return {{toolbox: string, toolboxButton: string, toolboxOpened: string}}\n */\n static get CSS() {\n\n return {\n toolbox: 'ce-toolbox',\n toolboxButton: 'ce-toolbox__button',\n toolboxOpened: 'ce-toolbox--opened',\n };\n\n }\n\n /**\n * Makes the Toolbox\n */\n make() {\n\n this.nodes.toolbox = $.make('div', Toolbox.CSS.toolbox);\n $.append(this.Editor.Toolbar.nodes.content, this.nodes.toolbox);\n\n this.addTools();\n\n }\n\n /**\n * Iterates available tools and appends them to the Toolbox\n */\n addTools() {\n\n let tools = this.Editor.Tools.toolsAvailable;\n\n for (let toolName in tools) {\n\n this.addTool(toolName, tools[toolName]);\n\n }\n\n }\n\n /**\n * Append Tool to the Toolbox\n *\n * @param {string} toolName - tool name\n * @param {Tool} tool - tool class\n */\n addTool(toolName, tool) {\n\n if (tool.displayInToolbox && !tool.iconClassName) {\n\n _.log('Toolbar icon class name is missed. Tool %o skipped', 'warn', toolName);\n return;\n\n }\n\n /**\n * @todo Add checkup for the render method\n */\n // if (typeof tool.render !== 'function') {\n //\n // _.log('render method missed. Tool %o skipped', 'warn', tool);\n // return;\n //\n // }\n\n /**\n * Skip tools that pass 'displayInToolbox=false'\n */\n if (!tool.displayInToolbox) {\n\n return;\n\n }\n\n let button = $.make('li', [Toolbox.CSS.toolboxButton, tool.iconClassName], {\n title: toolName\n });\n\n /**\n * Save tool's name in the button data-name\n */\n button.dataset.name = toolName;\n\n $.append(this.nodes.toolbox, button);\n\n this.nodes.toolbox.appendChild(button);\n this.nodes.buttons.push(button);\n\n /**\n * @todo add event with module Listeners\n */\n // this.Editor.Listeners.add();\n button.addEventListener('click', event => {\n\n this.buttonClicked(event);\n\n }, false);\n\n }\n\n /**\n * Toolbox button click listener\n * 1) if block is empty -> replace\n * 2) if block is not empty -> add new block below\n *\n * @param {MouseEvent} event\n */\n buttonClicked(event) {\n\n let toolButton = event.target,\n toolName = toolButton.dataset.name,\n tool = this.Editor.Tools.toolClasses[toolName];\n\n /**\n * @type {Block}\n */\n let currentBlock = this.Editor.BlockManager.currentBlock;\n\n /**\n * We do replace if:\n * - block is empty\n * - block is not irreplaceable\n * @type {Array}\n */\n if (!tool.irreplaceable && currentBlock.isEmpty) {\n\n this.Editor.BlockManager.replace(toolName);\n\n } else {\n\n this.Editor.BlockManager.insert(toolName);\n\n }\n\n /**\n * @todo set caret to the new block\n */\n\n // window.setTimeout(function () {\n\n /** Set caret to current block */\n // editor.caret.setToBlock(currentInputIndex);\n\n // }, 10);\n\n /**\n * Move toolbar when node is changed\n */\n this.Editor.Toolbar.move();\n\n }\n\n /**\n * Open Toolbox with Tools\n */\n open() {\n\n this.nodes.toolbox.classList.add(Toolbox.CSS.toolboxOpened);\n this.opened = true;\n\n }\n\n /**\n * Close Toolbox\n */\n close() {\n\n this.nodes.toolbox.classList.remove(Toolbox.CSS.toolboxOpened);\n this.opened = false;\n\n }\n\n /**\n * Close Toolbox\n */\n toggle() {\n\n if (!this.opened) {\n\n this.open();\n\n } else {\n\n this.close();\n\n }\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/toolbox.js","/**\n * @module Codex Editor Tools Submodule\n *\n * Creates Instances from Plugins and binds external config to the instances\n */\n\n/**\n * Each Tool must contain the following important objects:\n *\n * @typedef {Object} ToolConfig {@link docs/tools.md}\n * @property {String} iconClassname - this a icon in toolbar\n * @property {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE\n * @property {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE\n * @property render @todo add description\n * @property save @todo add description\n * @property settings @todo add description\n * @property validate - method that validates output data before saving\n */\n\n/**\n * @typedef {Function} Tool {@link docs/tools.md}\n * @property {Boolean} displayInToolbox - By default, tools won't be added in the Toolbox. Pass true to add.\n * @property {String} iconClassName - CSS class name for the Toolbox button\n * @property {Boolean} irreplaceable - Toolbox behaviour: replace or add new block below\n * @property render\n * @property save\n * @property settings\n * @property validate\n *\n * @todo update according to current API\n * @todo describe Tool in the {@link docs/tools.md}\n */\n\n/**\n * Class properties:\n *\n * @typedef {Tools} Tools\n * @property {Tools[]} toolsAvailable - available Tools\n * @property {Tools[]} toolsUnavailable - unavailable Tools\n * @property {Object} toolsClasses - all classes\n * @property {EditorConfig} config - Editor config\n */\nexport default class Tools extends Module {\n\n /**\n * Returns available Tools\n * @return {Tool[]}\n */\n get available() {\n\n return this.toolsAvailable;\n\n }\n\n /**\n * Returns unavailable Tools\n * @return {Tool[]}\n */\n get unavailable() {\n\n return this.toolsUnavailable;\n\n }\n\n /**\n * Static getter for default Tool config fields\n *\n * @usage Tools.defaultConfig.displayInToolbox\n * @return {ToolConfig}\n */\n static get defaultConfig() {\n\n return {\n iconClassName : '',\n displayInToolbox : false,\n enableLineBreaks : false,\n irreplaceable : false\n };\n\n }\n\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor({config}) {\n\n super({config});\n\n /**\n * Map {name: Class, ...} where:\n * name — block type name in JSON. Got from EditorConfig.tools keys\n * @type {Object}\n */\n this.toolClasses = {};\n\n /**\n * Available tools list\n * {name: Class, ...}\n * @type {Object}\n */\n this.toolsAvailable = {};\n\n /**\n * Tools that rejected a prepare method\n * {name: Class, ... }\n * @type {Object}\n */\n this.toolsUnavailable = {};\n\n }\n\n /**\n * Creates instances via passed or default configuration\n * @return {Promise}\n */\n prepare() {\n\n if (!this.config.hasOwnProperty('tools')) {\n\n return Promise.reject(\"Can't start without tools\");\n\n }\n\n for(let toolName in this.config.tools) {\n\n this.toolClasses[toolName] = this.config.tools[toolName];\n\n }\n\n /**\n * getting classes that has prepare method\n */\n let sequenceData = this.getListOfPrepareFunctions();\n\n /**\n * if sequence data contains nothing then resolve current chain and run other module prepare\n */\n if (sequenceData.length === 0) {\n\n return Promise.resolve();\n\n }\n\n /**\n * to see how it works {@link Util#sequence}\n */\n return _.sequence(sequenceData, (data) => {\n\n this.success(data);\n\n }, (data) => {\n\n this.fallback(data);\n\n });\n\n }\n\n /**\n * Binds prepare function of plugins with user or default config\n * @return {Array} list of functions that needs to be fired sequentially\n */\n getListOfPrepareFunctions() {\n\n let toolPreparationList = [];\n\n for(let toolName in this.toolClasses) {\n\n let toolClass = this.toolClasses[toolName];\n\n if (typeof toolClass.prepare === 'function') {\n\n toolPreparationList.push({\n function : toolClass.prepare,\n data : {\n toolName\n }\n });\n\n } else {\n\n /**\n * If Tool hasn't a prepare method, mark it as available\n */\n this.toolsAvailable[toolName] = toolClass;\n\n }\n\n }\n\n return toolPreparationList;\n\n }\n\n /**\n * @param {ChainData.data} data - append tool to available list\n */\n success(data) {\n\n this.toolsAvailable[data.toolName] = this.toolClasses[data.toolName];\n\n }\n\n /**\n * @param {ChainData.data} data - append tool to unavailable list\n */\n fallback(data) {\n\n this.toolsUnavailable[data.toolName] = this.toolClasses[data.toolName];\n\n }\n\n /**\n * Return tool`a instance\n *\n * @param {String} tool — tool name\n * @param {Object} data — initial data\n *\n * @todo throw exceptions if tool doesnt exist\n *\n */\n construct(tool, data) {\n\n let plugin = this.toolClasses[tool],\n config = this.config.toolsConfig[tool];\n\n if (!config) {\n\n config = this.defaultConfig;\n\n }\n\n let instance = new plugin(data, config);\n\n return instance;\n\n }\n\n /**\n * Check if passed Tool is an instance of Initial Block Tool\n * @param {Tool} tool - Tool to check\n * @return {Boolean}\n */\n isInitial(tool) {\n\n return tool instanceof this.available[this.config.initialBlock];\n\n }\n\n}\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/tools.js","/**\n * Module UI\n *\n * @type {UI}\n */\n// let className = {\n\n/**\n * @const {string} BLOCK_CLASSNAME - redactor blocks name\n */\n// BLOCK_CLASSNAME : 'ce-block',\n\n/**\n * @const {String} wrapper for plugins content\n */\n// BLOCK_CONTENT : 'ce-block__content',\n\n/**\n * @const {String} BLOCK_STRETCHED - makes block stretched\n */\n// BLOCK_STRETCHED : 'ce-block--stretched',\n\n/**\n * @const {String} BLOCK_HIGHLIGHTED - adds background\n */\n// BLOCK_HIGHLIGHTED : 'ce-block--focused',\n\n/**\n * @const {String} - for all default settings\n */\n// SETTINGS_ITEM : 'ce-settings__item'\n// };\n\nimport Block from '../block';\n\n/**\n * @class\n *\n * @classdesc Makes CodeX Editor UI:\n * \n * \n * \n * \n * \n *\n * @typedef {UI} UI\n * @property {EditorConfig} config - editor configuration {@link CodexEditor#configuration}\n * @property {Object} Editor - available editor modules {@link CodexEditor#moduleInstances}\n * @property {Object} nodes -\n * @property {Element} nodes.holder - element where we need to append redactor\n * @property {Element} nodes.wrapper - \n * @property {Element} nodes.redactor - \n */\nexport default class UI extends Module {\n\n /**\n * @constructor\n *\n * @param {EditorConfig} config\n */\n constructor({config}) {\n\n super({config});\n\n this.nodes = {\n holder: null,\n wrapper: null,\n redactor: null\n };\n\n }\n\n /**\n * @protected\n *\n * Making main interface\n */\n prepare() {\n\n return this.make()\n /**\n * Make toolbar\n */\n .then(() => this.Editor.Toolbar.make())\n /**\n * Load and append CSS\n */\n .then(() => this.loadStyles())\n /**\n * Bind events for the UI elements\n */\n .then(() => this.bindEvents())\n\n /** Make container for inline toolbar */\n // .then(makeInlineToolbar_)\n\n /** Add inline toolbar tools */\n // .then(addInlineToolbarTools_)\n\n /** Draw wrapper for notifications */\n // .then(makeNotificationHolder_)\n\n /** Add eventlisteners to redactor elements */\n // .then(bindEvents_)\n\n .catch(e => {\n\n console.error(e);\n\n // editor.core.log(\"Can't draw editor interface\");\n\n });\n\n }\n\n /**\n * CodeX Editor UI CSS class names\n * @return {{editorWrapper: string, editorZone: string, block: string}}\n */\n get CSS() {\n\n return {\n editorWrapper : 'codex-editor',\n editorZone : 'codex-editor__redactor',\n };\n\n }\n\n /**\n * Makes CodeX Editor interface\n * @return {Promise}\n */\n make() {\n\n return new Promise( (resolve, reject) => {\n\n /**\n * Element where we need to append CodeX Editor\n * @type {Element}\n */\n this.nodes.holder = document.getElementById(this.config.holderId);\n\n if (!this.nodes.holder) {\n\n reject(Error(\"Holder wasn't found by ID: #\" + this.config.holderId));\n return;\n\n }\n\n /**\n * Create and save main UI elements\n */\n this.nodes.wrapper = $.make('div', this.CSS.editorWrapper);\n this.nodes.redactor = $.make('div', this.CSS.editorZone);\n\n this.nodes.wrapper.appendChild(this.nodes.redactor);\n this.nodes.holder.appendChild(this.nodes.wrapper);\n\n resolve();\n\n });\n\n }\n\n /**\n * Appends CSS\n */\n loadStyles() {\n\n /**\n * Load CSS\n */\n let styles = require('../../styles/main.css');\n\n /**\n * Make tag\n */\n let tag = $.make('style', null, {\n textContent: styles.toString()\n });\n\n /**\n * Append styles\n */\n $.append(document.head, tag);\n\n }\n\n /**\n * Bind events on the CodeX Editor interface\n */\n bindEvents() {\n\n /**\n * @todo bind events with the Listeners module\n */\n this.nodes.redactor.addEventListener('click', event => this.redactorClicked(event), false );\n\n }\n\n /**\n * All clicks on the redactor zone\n *\n * @param {MouseEvent} event\n *\n * @description\n * 1. Save clicked Block as a current {@link BlockManager#currentNode}\n * it uses for the following:\n * - add CSS modifier for the selected Block\n * - on Enter press, we make a new Block under that\n *\n * 2. Move and show the Toolbar\n *\n * 3. Set a Caret\n *\n * 4. By clicks on the Editor's bottom zone:\n * - if last Block is empty, set a Caret to this\n * - otherwise, add a new empty Block and set a Caret to that\n *\n * 5. Hide the Inline Toolbar\n *\n * @see selectClickedBlock\n *\n */\n redactorClicked(event) {\n\n let clickedNode = event.target;\n\n /**\n * Select clicked Block as Current\n */\n try {\n\n this.Editor.BlockManager.setCurrentBlockByChildNode(clickedNode);\n\n /**\n * If clicked outside first-level Blocks, set Caret to the last empty Block\n */\n\n } catch (e) {\n\n this.Editor.Caret.setToTheLastBlock();\n\n }\n\n\n\n\n /**\n * @todo hide the Inline Toolbar\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 /**\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 this.Editor.Toolbar.move();\n this.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\n /**\n * Hide the Plus Button\n * */\n this.Editor.Toolbar.plusButton.hide();\n\n /**\n * Show the Plus Button if:\n * - Block is an initial-block (Text)\n * - Block is empty\n */\n let isInitialBlock = this.Editor.Tools.isInitial(this.Editor.BlockManager.currentBlock.tool),\n isEmptyBlock = this.Editor.BlockManager.currentBlock.isEmpty;\n\n if (isInitialBlock && isEmptyBlock) {\n\n this.Editor.Toolbar.plusButton.show();\n\n }\n\n }\n\n}\n\n// /**\n// * Codex Editor UI module\n// *\n// * @author Codex Team\n// * @version 1.2.0\n// */\n//\n// module.exports = (function (ui) {\n//\n// let editor = codex.editor;\n//\n// /**\n// * Basic editor classnames\n// */\n// ui.prepare = function () {\n//\n\n//\n// };\n//\n// /** Draw notifications holder */\n// var makeNotificationHolder_ = function () {\n//\n// /** Append block with notifications to the document */\n// editor.nodes.notifications = editor.notifications.createHolder();\n//\n// };\n//\n//\n// var addInlineToolbarTools_ = function () {\n//\n// var tools = {\n//\n// bold: {\n// icon : 'ce-icon-bold',\n// command : 'bold'\n// },\n//\n// italic: {\n// icon : 'ce-icon-italic',\n// command : 'italic'\n// },\n//\n// link: {\n// icon : 'ce-icon-link',\n// command : 'createLink'\n// }\n// };\n//\n// var toolButton,\n// tool;\n//\n// for(var name in tools) {\n//\n// tool = tools[name];\n//\n// toolButton = editor.draw.toolbarButtonInline(name, tool.icon);\n//\n// editor.nodes.inlineToolbar.buttons.appendChild(toolButton);\n// /**\n// * Add callbacks to this buttons\n// */\n// editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);\n//\n// }\n//\n// };\n//\n// /**\n// * @private\n// * Bind editor UI events\n// */\n// var bindEvents_ = function () {\n//\n// editor.core.log('ui.bindEvents fired', 'info');\n//\n// // window.addEventListener('error', function (errorMsg, url, lineNumber) {\n// // editor.notifications.errorThrown(errorMsg, event);\n// // }, false );\n//\n// /** All keydowns on Document */\n// editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);\n//\n// /** All keydowns on Redactor zone */\n// editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);\n//\n// /** All keydowns on Document */\n// editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );\n//\n// /**\n// * Mouse click to radactor\n// */\n// editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );\n//\n// /**\n// * Clicks to the Plus button\n// */\n// editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);\n//\n// /**\n// * Clicks to SETTINGS button in toolbar\n// */\n// editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );\n//\n// /** Bind click listeners on toolbar buttons */\n// for (var button in editor.nodes.toolbarButtons) {\n//\n// editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);\n//\n// }\n//\n// };\n//\n// ui.addBlockHandlers = function (block) {\n//\n// if (!block) return;\n//\n// /**\n// * Block keydowns\n// */\n// editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);\n//\n// /**\n// * Pasting content from another source\n// * We have two type of sanitization\n// * First - uses deep-first search algorithm to get sub nodes,\n// * sanitizes whole Block_content and replaces cleared nodes\n// * This method is deprecated\n// * Method is used in editor.callback.blockPaste(event)\n// *\n// * Secont - uses Mutation observer.\n// * Observer \"observe\" DOM changes and send changings to callback.\n// * Callback gets changed node, not whole Block_content.\n// * Inserted or changed node, which we've gotten have been cleared and replaced with diry node\n// *\n// * Method is used in editor.callback.blockPasteViaSanitize(event)\n// *\n// * @uses html-janitor\n// * @example editor.callback.blockPasteViaSanitize(event), the second method.\n// *\n// */\n// editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);\n//\n// /**\n// * Show inline toolbar for selected text\n// */\n// editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);\n// editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);\n//\n// };\n//\n// /** getting all contenteditable elements */\n// ui.saveInputs = function () {\n//\n// var redactor = editor.nodes.redactor;\n//\n// editor.state.inputs = [];\n//\n// /** Save all inputs in global variable state */\n// var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');\n//\n// Array.prototype.map.call(inputs, function (current) {\n//\n// if (!current.type || current.type == 'text' || current.type == 'textarea') {\n//\n// editor.state.inputs.push(current);\n//\n// }\n//\n// });\n//\n// };\n//\n// /**\n// * Adds first initial block on empty redactor\n// */\n// ui.addInitialBlock = function () {\n//\n// var initialBlockType = editor.settings.initialBlockPlugin,\n// initialBlock;\n//\n// if ( !editor.tools[initialBlockType] ) {\n//\n// editor.core.log('Plugin %o was not implemented and can\\'t be used as initial block', 'warn', initialBlockType);\n// return;\n//\n// }\n//\n// initialBlock = editor.tools[initialBlockType].render();\n//\n// initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);\n//\n// editor.content.insertBlock({\n// type : initialBlockType,\n// block : initialBlock\n// });\n//\n// editor.content.workingNodeChanged(initialBlock);\n//\n// };\n//\n// ui.setInlineToolbarButtonBehaviour = function (button, type) {\n//\n// editor.listeners.add(button, 'mousedown', function (event) {\n//\n// editor.toolbar.inline.toolClicked(event, type);\n//\n// }, false);\n//\n// };\n//\n// return ui;\n//\n// })({});\n\n\n\n// WEBPACK FOOTER //\n// ./src/components/modules/ui.js","exports = module.exports = require(\"../../node_modules/css-loader/lib/css-base.js\")(undefined);\n// imports\n\n\n// module\nexports.push([module.id, \":root {\\n\\n /**\\n * Toolbar buttons\\n */\\n\\n /**\\n * Block content width\\n */\\n\\n /**\\n * Toolbar Plus Button and Toolbox buttons height and width\\n */\\n\\n}\\n/**\\n* Editor wrapper\\n*/\\n.codex-editor {\\n position: relative;\\n border: 1px solid #ccc;\\n padding: 10px;\\n box-sizing: border-box;\\n}\\n.codex-editor .hide {\\n display: none;\\n }\\n.codex-editor__redactor {\\n padding-bottom: 300px;\\n }\\n.ce-toolbar {\\n position: absolute;\\n left: 0;\\n right: 0;\\n top: 0;\\n opacity: 0;\\n visibility: hidden;\\n transition: opacity 100ms ease;\\n will-change: opacity, transform;\\n}\\n.ce-toolbar--opened {\\n opacity: 1;\\n visibility: visible;\\n }\\n.ce-toolbar__content {\\n max-width: 650px;\\n margin: 0 auto;\\n position: relative;\\n }\\n.ce-toolbar__plus {\\n position: absolute;\\n left: calc(-34px - 10px);\\n display: inline-block;\\n background-color: #eff2f5;\\n width: 34px;\\n height: 34px;\\n line-height: 34px;\\n text-align: center;\\n border-radius: 50%\\n }\\n.ce-toolbar__plus::after {\\n content: '+';\\n font-size: 26px;\\n display: block;\\n margin-top: -2px;\\n margin-right: -2px;\\n\\n}\\n.ce-toolbar__plus--hidden {\\n display: none;\\n\\n}\\n.ce-toolbox {\\n visibility: hidden;\\n transition: opacity 100ms ease;\\n will-change: opacity;\\n}\\n.ce-toolbox--opened {\\n opacity: 1;\\n visibility: visible;\\n }\\n.ce-toolbox__button {\\n display: inline-block;\\n list-style: none;\\n margin: 0;\\n background: #eff2f5;\\n width: 34px;\\n height: 34px;\\n border-radius: 30px;\\n overflow: hidden;\\n text-align: center;\\n line-height: 34px\\n }\\n.ce-toolbox__button::before {\\n content: attr(title);\\n font-size: 22px;\\n font-weight: 500;\\n letter-spacing: 1em;\\n -webkit-font-feature-settings: \\\"smcp\\\", \\\"c2sc\\\";\\n font-feature-settings: \\\"smcp\\\", \\\"c2sc\\\";\\n font-variant-caps: all-small-caps;\\n padding-left: 11.5px;\\n margin-top: -1px;\\n display: inline-block;\\n\\n}\\n.ce-block {\\n border: 1px dotted #ccc;\\n margin: 2px 0;\\n}\\n.ce-block--selected {\\n background-color: #eff2f5;\\n }\\n.ce-block__content {\\n max-width: 650px;\\n margin: 0 auto;\\n }\\n\", \"\"]);\n\n// exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/styles/main.css\n// module id = 15\n// module chunks = 0","/*\n\tMIT License http://www.opensource.org/licenses/mit-license.php\n\tAuthor Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\nmodule.exports = function(useSourceMap) {\n\tvar list = [];\n\n\t// return the list of modules as css string\n\tlist.toString = function toString() {\n\t\treturn this.map(function (item) {\n\t\t\tvar content = cssWithMappingToString(item, useSourceMap);\n\t\t\tif(item[2]) {\n\t\t\t\treturn \"@media \" + item[2] + \"{\" + content + \"}\";\n\t\t\t} else {\n\t\t\t\treturn content;\n\t\t\t}\n\t\t}).join(\"\");\n\t};\n\n\t// import a list of modules into the list\n\tlist.i = function(modules, mediaQuery) {\n\t\tif(typeof modules === \"string\")\n\t\t\tmodules = [[null, modules, \"\"]];\n\t\tvar alreadyImportedModules = {};\n\t\tfor(var i = 0; i < this.length; i++) {\n\t\t\tvar id = this[i][0];\n\t\t\tif(typeof id === \"number\")\n\t\t\t\talreadyImportedModules[id] = true;\n\t\t}\n\t\tfor(i = 0; i < modules.length; i++) {\n\t\t\tvar item = modules[i];\n\t\t\t// skip already imported module\n\t\t\t// this implementation is not 100% perfect for weird media query combinations\n\t\t\t// when a module is imported multiple times with different media queries.\n\t\t\t// I hope this will never occur (Hey this way we have smaller bundles)\n\t\t\tif(typeof item[0] !== \"number\" || !alreadyImportedModules[item[0]]) {\n\t\t\t\tif(mediaQuery && !item[2]) {\n\t\t\t\t\titem[2] = mediaQuery;\n\t\t\t\t} else if(mediaQuery) {\n\t\t\t\t\titem[2] = \"(\" + item[2] + \") and (\" + mediaQuery + \")\";\n\t\t\t\t}\n\t\t\t\tlist.push(item);\n\t\t\t}\n\t\t}\n\t};\n\treturn list;\n};\n\nfunction cssWithMappingToString(item, useSourceMap) {\n\tvar content = item[1] || '';\n\tvar cssMapping = item[3];\n\tif (!cssMapping) {\n\t\treturn content;\n\t}\n\n\tif (useSourceMap && typeof btoa === 'function') {\n\t\tvar sourceMapping = toComment(cssMapping);\n\t\tvar sourceURLs = cssMapping.sources.map(function (source) {\n\t\t\treturn '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'\n\t\t});\n\n\t\treturn [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n\t}\n\n\treturn [content].join('\\n');\n}\n\n// Adapted from convert-source-map (MIT)\nfunction toComment(sourceMap) {\n\t// eslint-disable-next-line no-undef\n\tvar base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n\tvar data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;\n\n\treturn '/*# ' + data + ' */';\n}\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./node_modules/css-loader/lib/css-base.js\n// module id = 16\n// module chunks = 0"],"sourceRoot":""} \ No newline at end of file diff --git a/docs/tools.md b/docs/tools.md new file mode 100644 index 00000000..b6be8d92 --- /dev/null +++ b/docs/tools.md @@ -0,0 +1,24 @@ +# CodeX Editor Tools + +CodeX Editor is a block-oriented editor. It means that entry composed with the list of `Blocks` of different types: `Texts`, `Headers`, `Images`, `Quotes` etc. + +`Tool` — is a class that provide custom `Block` type. All Tools represented by `Plugins`. + +## Tool class structure + +### Constructor + +### Save + +### Render + +### Available settings + +| Name | Type | Default Value | Description | +| -- | -- | -- | -- | +| `displayInToolbox` | _Boolean_ | `false` | Pass `true` to display this `Tool` in the Editor's `Toolbox` | +| `iconClassName` | _String_ | — | CSS class name for the `Toolbox` icon. Used when `displayInToolbox` is `true` | +| `irreplaceable` | _Boolean_ | `false` | By default, **empty** `Blocks` can be **replaced** by other `Blocks` with the `Toolbox`. Some tools with media-content may prefer another behaviour. Pass `true` and `Toolbox` will add a new block below yours. | +| `contentless` | _Boolean_ | `false` | Pass `true` for Tool which represents decorative empty `Blocks` | + +### Sanitize diff --git a/example/example.html b/example/example.html index f545e048..9b4c6a50 100644 --- a/example/example.html +++ b/example/example.html @@ -9,11 +9,6 @@ font-size: 14px; line-height: 1.5em; } - - #codex-editor { - margin: 0 auto; - max-width: 800px; - } @@ -22,8 +17,8 @@ - - + + @@ -65,9 +60,9 @@ codex.editor = 1; var editor = new CodexEditor({ holderId : 'codex-editor', - initialBlock : 'paragraph', + initialBlock : 'text', tools: { - paragraph: Paragraph, + text: Text, }, toolsConfig: { quote: { @@ -79,13 +74,13 @@ data: { items: [ { - type : 'paragraph', + type : 'text', data : { text : 'Привет от CodeX' } }, { - type : 'paragraph', + type : 'text', data : { text : 'Пишите нам на team@ifmo.su' } @@ -100,17 +95,17 @@ // }); // codex.editor.start({ // holderId : "codex-editor", -// initialBlockPlugin : 'paragraph', +// initialBlockPlugin : 'text', // // placeholder: 'Прошлой ночью мне приснилось...', // hideToolbar: false, // tools : { -// paragraph: { -// type: 'paragraph', -// iconClassname: 'ce-icon-paragraph', -// render: paragraph.render, -// validate: paragraph.validate, -// save: paragraph.save, -// destroy: paragraph.destroy, +// text: { +// type: 'text', +// iconClassname: 'ce-icon-text', +// render: text.render, +// validate: text.validate, +// save: text.save, +// destroy: text.destroy, // allowedToPaste: true, // showInlineToolbar: true, // allowRenderOnPaste: true @@ -272,7 +267,7 @@ // } // }, // { -// type : 'paragraph', +// type : 'text', // data : { // text : 'Пишите нам на team@ifmo.su' // } diff --git a/example/plugins/paragraph/paragraph.css b/example/plugins/text/text.css similarity index 84% rename from example/plugins/paragraph/paragraph.css rename to example/plugins/text/text.css index 7651db45..654ae4a7 100644 --- a/example/plugins/paragraph/paragraph.css +++ b/example/plugins/text/text.css @@ -2,9 +2,10 @@ * Empty paragraph placeholder */ -.ce-paragraph { - padding: 0.7em 0 !important; - line-height: 1.7em; +.ce-text { + padding: 15px 0 !important; + line-height: 1.6em; + outline: none; } .ce-paragraph:empty::before, diff --git a/example/plugins/paragraph/paragraph.js b/example/plugins/text/text.js similarity index 70% rename from example/plugins/paragraph/paragraph.js rename to example/plugins/text/text.js index 04657907..c0732587 100644 --- a/example/plugins/paragraph/paragraph.js +++ b/example/plugins/text/text.js @@ -1,5 +1,5 @@ /** - * @class Paragraph + * @class Text * @classdesc Paragraph plugin for CodexEditor * * @author CodeX Team (team@ifmo.su) @@ -8,33 +8,44 @@ * @version 2.0.0 * * - * @typedef {Object} ParagraphData - * @property {String} text — HTML content to insert to paragraph element + * @typedef {Object} TextData + * @property {String} text — HTML content to insert to text element * */ -class Paragraph { +class Text { /** - * Get the name of the plugin + * Pass true to display this tool in the Editor's Toolbox * - * @returns {string} The plugin name + * @returns {boolean} */ - static get name() { + static get displayInToolbox() { - return 'paragraph'; + return true; + + } + + /** + * Class for the Toolbox icon + * + * @returns {string} + */ + static get iconClassName() { + + return 'cdx-text-icon'; } /** * Render plugin`s html and set initial content * - * @param {ParagraphData} data — initial plugin content + * @param {TextData} data — initial plugin content */ constructor(data = {}) { this._CSS = { - wrapper: 'ce-paragraph' + wrapper: 'ce-text' }; this._data = {}; @@ -65,7 +76,7 @@ class Paragraph { /** * Check if saved text is empty * - * @param {ParagraphData} savedData — data received from plugins`s element + * @param {TextData} savedData — data received from plugins`s element * @returns {boolean} false if saved text is empty, true otherwise */ validate(savedData) { @@ -96,7 +107,7 @@ class Paragraph { * * @todo sanitize data while saving * - * @returns {ParagraphData} Current data + * @returns {TextData} Current data */ get data() { @@ -111,7 +122,7 @@ class Paragraph { /** * Set new data for plugin * - * @param {ParagraphData} data — data to set + * @param {TextData} data — data to set */ set data(data) { diff --git a/package-lock.json b/package-lock.json index 672e07f6..112240f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,9 +51,9 @@ } }, "ajv": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.0.tgz", - "integrity": "sha1-6yhAdG6dxIvV4GOjbj/UAMXqtak=", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { "co": "4.6.0", @@ -1225,12 +1225,6 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "complex.js": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.0.4.tgz", - "integrity": "sha512-Syl95HpxUTS0QjwNxencZsKukgh1zdS9uXeXX2Us0pHaqBR6kiZZi0AkZ9VpZFwHJyVIUVzI4EumjWdXP3fy6w==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1543,12 +1537,6 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, - "decimal.js": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-7.2.3.tgz", - "integrity": "sha512-AoFI37QS0S87Ft0r3Bdz4q9xSpm1Paa9lSeKLXgMPk/u/+QPIM5Gy4DHcZQS1seqPJH4gHLauPGn347z0HbsrA==", - "dev": true - }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -1669,12 +1657,12 @@ } }, "errno": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", - "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.6.tgz", + "integrity": "sha512-IsORQDpaaSwcDP4ZZnHxgE85werpo34VYn1Ud3mq+eUsF593faR8oCZNXrROVkpFu2TsbrNhHin0aUrTsQ9vNw==", "dev": true, "requires": { - "prr": "0.0.0" + "prr": "1.0.1" } }, "error-ex": { @@ -1783,12 +1771,12 @@ } }, "eslint": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.12.1.tgz", - "integrity": "sha512-28hOYej+NZ/R5H1yMvyKa1+bPlu+fnsIAQffK6hxXgvmXnImos2bA5XfCn5dYv2k2mrKj+/U/Z4L5ICWxC7TQw==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.13.1.tgz", + "integrity": "sha512-UCJVV50RtLHYzBp1DZ8CMPtRSg4iVZvjgO9IJHIKyWU/AnJVjtdRikoUPLB29n5pzMB7TnsLQWf0V6VUJfoPfw==", "dev": true, "requires": { - "ajv": "5.5.0", + "ajv": "5.5.2", "babel-code-frame": "6.26.0", "chalk": "2.3.0", "concat-stream": "1.6.0", @@ -1803,11 +1791,11 @@ "file-entry-cache": "2.0.0", "functional-red-black-tree": "1.0.1", "glob": "7.1.2", - "globals": "11.0.1", + "globals": "11.1.0", "ignore": "3.3.7", "imurmurhash": "0.1.4", "inquirer": "3.3.0", - "is-resolvable": "1.0.0", + "is-resolvable": "1.0.1", "js-yaml": "3.10.0", "json-stable-stringify-without-jsonify": "1.0.1", "levn": "0.3.0", @@ -1869,9 +1857,9 @@ "dev": true }, "globals": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.0.1.tgz", - "integrity": "sha1-Eqh7sBDlFUOWrMU14eQ/x1Ow5eg=", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.1.0.tgz", + "integrity": "sha512-uEuWt9mqTlPDwSqi+sHjD4nWU/1N+q0fiWI9T1mZpD2UENqX20CFD5T/ziLZvztPaBKl7ZylUi1q6Qfm7E2CiQ==", "dev": true }, "has-flag": { @@ -2200,12 +2188,6 @@ "for-in": "1.0.2" } }, - "fraction.js": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.2.tgz", - "integrity": "sha512-OswcigOSil3vYXgrPSx4NCaSyPikXqVNYN/4CyhS0ucVOJ4GVYr6KQQLLcAudvS/4bBOzxqJ3XIsFaaMjl98ZQ==", - "dev": true - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3679,13 +3661,10 @@ "dev": true }, "is-resolvable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", - "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", - "dev": true, - "requires": { - "tryit": "1.0.3" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", + "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==", + "dev": true }, "is-stream": { "version": "1.1.0", @@ -3729,12 +3708,6 @@ "isarray": "1.0.0" } }, - "javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=", - "dev": true - }, "js-base64": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.0.tgz", @@ -3981,21 +3954,6 @@ "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", "dev": true }, - "mathjs": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-3.17.0.tgz", - "integrity": "sha512-bFDSjjLV3+csekog1L6z3FjZ0uSkRPFcMlbLef8KXxq68jtQQ48W2f+JKJugM9y6KxJEtt1zWFIGQnYKWR0nxg==", - "dev": true, - "requires": { - "complex.js": "2.0.4", - "decimal.js": "7.2.3", - "fraction.js": "4.0.2", - "javascript-natural-sort": "0.7.1", - "seed-random": "2.2.0", - "tiny-emitter": "2.0.0", - "typed-function": "0.10.6" - } - }, "md5.js": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", @@ -4033,7 +3991,7 @@ "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "dev": true, "requires": { - "errno": "0.1.4", + "errno": "0.1.6", "readable-stream": "2.3.3" } }, @@ -6959,14 +6917,67 @@ "dev": true }, "postcss-sass": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.1.0.tgz", - "integrity": "sha1-DSplW10kHsj0Gbs9o43lyhF0bds=", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.2.0.tgz", + "integrity": "sha512-cUmYzkP747fPCQE6d+CH2l1L4VSyIlAzZsok3HPjb5Gzsq3jE+VjpAdGlPsnQ310WKWI42sw+ar0UNN59/f3hg==", "dev": true, "requires": { "gonzales-pe": "4.2.3", - "mathjs": "3.17.0", - "postcss": "5.2.18" + "postcss": "6.0.14" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz", + "integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "source-map": "0.6.1", + "supports-color": "4.5.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, "postcss-scss": { @@ -7184,16 +7195,16 @@ } }, "postcss-smart-import": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/postcss-smart-import/-/postcss-smart-import-0.7.5.tgz", - "integrity": "sha512-Bs9wAFxH5irGpenBg9a65jTcydZLh7VBTX6NYwMXvVXO6y9CQ83kRmfpQDs5lHhl6IODeIeQfJep5HBMd9UVCQ==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/postcss-smart-import/-/postcss-smart-import-0.7.6.tgz", + "integrity": "sha512-9OpXaQ1uMMHWafUh0RWIpAKa3xxUDC2yyxicUPpGffH33nzbZG4/z+nk5Ocw5gGZ+3qkXV91iDV23Cmxf2Jhew==", "dev": true, "requires": { "babel-runtime": "6.26.0", "lodash": "4.17.4", "object-assign": "4.1.1", "postcss": "6.0.14", - "postcss-sass": "0.1.0", + "postcss-sass": "0.2.0", "postcss-scss": "1.0.2", "postcss-value-parser": "3.3.0", "promise-each": "2.2.0", @@ -7348,9 +7359,9 @@ } }, "prr": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", - "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, "pseudomap": { @@ -7823,12 +7834,6 @@ } } }, - "seed-random": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", - "integrity": "sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ=", - "dev": true - }, "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", @@ -8147,7 +8152,7 @@ "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "dev": true, "requires": { - "ajv": "5.5.0", + "ajv": "5.5.2", "ajv-keywords": "2.1.1", "chalk": "2.3.0", "lodash": "4.17.4", @@ -8219,12 +8224,6 @@ "setimmediate": "1.0.5" } }, - "tiny-emitter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.0.tgz", - "integrity": "sha1-utMnrbGAS0KiMa+nQVMr2ITNCa0=", - "dev": true - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -8252,12 +8251,6 @@ "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, - "tryit": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", - "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", - "dev": true - }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -8273,12 +8266,6 @@ "prelude-ls": "1.1.2" } }, - "typed-function": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-0.10.6.tgz", - "integrity": "sha512-PYtsDjxyW3vq7Itn2RMz0cn6CrbybIY6XC2i9c1q1o/H94QW8B1Pf3wSsbBDOCMpN1i5jDRrlDsLXFaqXBpfHQ==", - "dev": true - }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -8443,14 +8430,14 @@ } }, "webpack": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.9.0.tgz", - "integrity": "sha512-SlBO3yUIhSohW7uCA5c0v03V32DsaXU3vDyUtHB8rubgTgfwl1nv+I+BQIScuQ6exu74wWT6brF/GDXxGLStuA==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz", + "integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==", "dev": true, "requires": { "acorn": "5.2.1", "acorn-dynamic-import": "2.0.2", - "ajv": "5.5.0", + "ajv": "5.5.2", "ajv-keywords": "2.1.1", "async": "2.6.0", "enhanced-resolve": "3.4.1", diff --git a/package.json b/package.json index 78f03b41..87ea4b73 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "babel-preset-es2015": "^6.24.1", "babel-runtime": "^6.26.0", "css-loader": "^0.28.7", - "eslint": "^4.11.0", + "eslint": "^4.13.1", "eslint-loader": "^1.9.0", "extract-text-webpack-plugin": "^3.0.2", "html-janitor": "^2.0.2", @@ -36,8 +36,8 @@ "postcss-nested": "^2.1.2", "postcss-nested-ancestors": "^1.0.0", "postcss-nesting": "^4.2.1", - "postcss-smart-import": "^0.7.5", - "webpack": "^3.8.1" + "postcss-smart-import": "^0.7.6", + "webpack": "^3.10.0" }, "dependencies": {} } diff --git a/src/codex.js b/src/codex.js index b53c5056..feba6bac 100644 --- a/src/codex.js +++ b/src/codex.js @@ -45,15 +45,30 @@ /** * @typedef {Object} EditorConfig - * @property {String} holderId - Element to append Editor - * @property {String} initialBlock - Tool name which will be initial - * @property {Object} tools - list of tools. The object value must be function (constructor) so that CodexEditor could make an instance - * @property {@link Tools#ToolsConfig} toolsConfig - tools configuration - * @property {Array} data - Blocks list in JSON-format + * @property {String} holderId - Element to append Editor + * @property {Array} data - Blocks list in JSON-format + * @property {Object} tools - Map for used Tools in format { name : Class, ... } + * @property {String} initialBlock - This Tool will be added by default + * @property {String} placeholder - First Block placeholder + * @property {Object} sanitizer - @todo fill desc + * @property {Boolean} hideToolbar - @todo fill desc + * @property {Object} toolsConfig - tools configuration {@link Tools#ToolsConfig} + */ + +/** + * Dynamically imported utils + * + * @typedef {Dom} $ - {@link components/dom.js} + * @typedef {Util} _ - {@link components/utils.js} */ 'use strict'; +/** + * Apply polyfills + */ +import 'components/polyfills'; + /** * Require Editor modules places in components/modules dir */ @@ -87,11 +102,19 @@ module.exports = class CodexEditor { /** * Configuration object + * @type {EditorConfig} */ this.config = {}; /** - * Editor Components + * @typedef {Object} EditorComponents + * @property {BlockManager} BlockManager + * @property {Tools} Tools + * @property {Events} Events + * @property {UI} UI + * @property {Toolbar} Toolbar + * @property {Toolbox} Toolbox + * @property {Renderer} Renderer */ this.moduleInstances = {}; @@ -110,7 +133,7 @@ module.exports = class CodexEditor { }) .catch(error => { - console.log('CodeX Editor does not ready beecause of %o', error); + console.log('CodeX Editor does not ready because of %o', error); }); @@ -118,9 +141,9 @@ module.exports = class CodexEditor { /** * Setting for configuration - * @param {Object} config + * @param {EditorConfig} config */ - set configuration(config = {}) { + set configuration(config) { this.config.holderId = config.holderId; this.config.placeholder = config.placeholder || 'write your story...'; @@ -135,11 +158,24 @@ module.exports = class CodexEditor { this.config.toolsConfig = config.toolsConfig || {}; this.config.data = config.data || []; + /** + * If initial Block's Tool was not passed, use the first Tool in config.tools + */ + if (!config.initialBlock) { + + for (this.config.initialBlock in this.config.tools) break; + + } else { + + this.config.initialBlock = config.initialBlock; + + } + } /** * Returns private property - * @returns {{}|*} + * @returns {EditorConfig} */ get configuration() { @@ -182,7 +218,6 @@ module.exports = class CodexEditor { * To prevent this, we use 'babel-plugin-class-display-name' plugin * @see https://www.npmjs.com/package/babel-plugin-class-display-name */ - this.moduleInstances[Module.displayName] = new Module({ config : this.configuration }); @@ -250,8 +285,8 @@ module.exports = class CodexEditor { let prepareDecorator = module => module.prepare(); return Promise.resolve() - .then(prepareDecorator(this.moduleInstances.UI)) .then(prepareDecorator(this.moduleInstances.Tools)) + .then(prepareDecorator(this.moduleInstances.UI)) .then(() => { if (this.config.data && this.config.data.items) { @@ -307,11 +342,11 @@ module.exports = class CodexEditor { // * holds initial settings // */ // editor.settings = { -// tools : ['paragraph', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'], +// tools : ['text', 'header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile'], // holderId : 'codex-editor', // // // Type of block showing on empty editor -// initialBlockPlugin: 'paragraph' +// initialBlockPlugin: 'text' // }; // // /** diff --git a/src/components/__module.js b/src/components/__module.js index 89afdbe1..d51c419f 100644 --- a/src/components/__module.js +++ b/src/components/__module.js @@ -1,7 +1,7 @@ /** * @abstract * @class Module - * @classdesc All modules inherites from this class. + * @classdesc All modules inherits from this class. * * @typedef {Module} Module * @property {Object} config - Editor user settings @@ -22,7 +22,14 @@ export default class Module { } + /** + * @type {EditorConfig} + */ this.config = config; + + /** + * @type {EditorComponents} + */ this.Editor = null; } diff --git a/src/components/block.js b/src/components/block.js index c00e0946..c51a7ca2 100644 --- a/src/components/block.js +++ b/src/components/block.js @@ -20,15 +20,24 @@ export default class Block { this.tool = tool; - this.CSS = { - wrapper: 'ce-block', - content: 'ce-block__content' - }; - this._html = this.compose(); } + /** + * CSS classes for the Block + * @return {{wrapper: string, content: string}} + */ + static get CSS() { + + return { + wrapper: 'ce-block', + content: 'ce-block__content', + selected: 'ce-block--selected' + }; + + } + /** * Make default block wrappers and put tool`s content there * @@ -37,8 +46,8 @@ export default class Block { */ compose() { - let wrapper = $.make('div', this.CSS.wrapper), - content = $.make('div', this.CSS.content); + let wrapper = $.make('div', Block.CSS.wrapper), + content = $.make('div', Block.CSS.content); content.appendChild(this.tool.html); wrapper.appendChild(content); @@ -58,4 +67,74 @@ export default class Block { } + /** + * Check block for emptiness + * + * @return {Boolean} + */ + get isEmpty() { + + /** + * Allow Tool to represent decorative contentless blocks: for example "* * *"-tool + * That Tools are not empty + */ + if (this.tool.contentless) { + + return false; + + } + + let emptyText = this._html.textContent.trim().length === 0, + emptyMedia = !this.hasMedia; + + return emptyText && emptyMedia; + + } + + /** + * Check if block has a media content such as images, iframes and other + * @return {Boolean} + */ + get hasMedia() { + + /** + * This tags represents media-content + * @type {string[]} + */ + const mediaTags = [ + 'img', + 'iframe', + 'video', + 'audio', + 'source', + 'input', + 'textarea', + 'twitterwidget' + ]; + + return !!this._html.querySelector(mediaTags.join(',')); + + } + + /** + * Set selected state + * @param {Boolean} state - 'true' to select, 'false' to remove selection + */ + set selected(state) { + + /** + * We don't need to mark Block as Selected when it is not empty + */ + if (state === true && !this.isEmpty) { + + this._html.classList.add(Block.CSS.selected); + + } else { + + this._html.classList.remove(Block.CSS.selected); + + } + + } + } \ No newline at end of file diff --git a/src/components/core.js b/src/components/core.js index 02f3c0f0..9d0ef702 100644 --- a/src/components/core.js +++ b/src/components/core.js @@ -99,42 +99,6 @@ export default class Core { } - /** - * Core custom logger - * - * @param msg - * @param type - * @param args - */ - log(msg, type, args) { - - type = type || 'log'; - - if (!args) { - - args = msg || 'undefined'; - msg = '[codex-editor]: %o'; - - } else { - - msg = '[codex-editor]: ' + msg; - - } - - try{ - - if ( 'console' in window && window.console[ type ] ) { - - if ( args ) window.console[ type ]( msg, args ); - else window.console[ type ]( msg ); - - } - - } catch(e) { - // do nothing - } - - } /** * Native Ajax diff --git a/src/components/dom.js b/src/components/dom.js index 3e074cd4..1a1897a5 100644 --- a/src/components/dom.js +++ b/src/components/dom.js @@ -92,7 +92,7 @@ export default class Dom { * @param {Object} node * @returns {boolean} */ - static isNode(node) { + static isElement(node) { return node && typeof node === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE; diff --git a/src/components/modules/_content.js b/src/components/modules/_content.js index d28a598d..6623ac8f 100644 --- a/src/components/modules/_content.js +++ b/src/components/modules/_content.js @@ -118,7 +118,7 @@ module.exports = class Content { */ getFirstLevelBlock(node) { - if (!$.isNode(node)) { + if (!$.isElement(node)) { node = node.parentNode; diff --git a/src/components/modules/blockManager.js b/src/components/modules/blockManager.js index 6966be3b..44e86334 100644 --- a/src/components/modules/blockManager.js +++ b/src/components/modules/blockManager.js @@ -7,15 +7,20 @@ import Block from '../block'; +/** + * @typedef {BlockManager} BlockManager + * @property {Number} currentBlockIndex - Index of current working block + * @property {Proxy} _blocks - Proxy for Blocks instance {@link Blocks} + */ export default class BlockManager extends Module { /** * @constructor * @param {EditorConfig} config */ - constructor(config) { + constructor({config}) { - super(config); + super({config}); /** * Proxy for Blocks instance {@link Blocks} @@ -78,13 +83,17 @@ export default class BlockManager extends Module { * @param {String} toolName — plugin name * @param {Object} data — plugin data */ - insert(toolName, data) { + insert(toolName, data = {}) { let toolInstance = this.Editor.Tools.construct(toolName, data), block = new Block(toolInstance); this._blocks[++this.currentBlockIndex] = block; + /** + * @todo fire Tool's appendCallback + */ + } /** @@ -93,13 +102,17 @@ export default class BlockManager extends Module { * @param {String} toolName — plugin name * @param {Object} data — plugin data */ - replace(toolName, data) { + replace(toolName, data = {}) { let toolInstance = this.Editor.Tools.construct(toolName, data), block = new Block(toolInstance); this._blocks.insert(this.currentBlockIndex, block, true); + /** + * @todo fire Tool's appendCallback + */ + } /** @@ -156,8 +169,23 @@ export default class BlockManager extends Module { let nodes = this._blocks.nodes; + /** + * Update current Block's index + * @type {number} + */ this.currentBlockIndex = nodes.indexOf(element); + /** + * Remove previous selected Block's state + */ + this._blocks.array.forEach( block => block.selected = false); + + /** + * Mark current Block as selected + * @type {boolean} + */ + this.currentBlock.selected = true; + } /** @@ -171,6 +199,38 @@ export default class BlockManager extends Module { } + /** + * 1) Find first-level Block from passed child Node + * 2) Mark it as current + * + * @param {Element|Text} childNode - look ahead from this node. + * @throws Error - when passed Node is not included at the Block + */ + setCurrentBlockByChildNode(childNode) { + + /** + * If node is Text TextNode + */ + if (!$.isElement(childNode)) { + + childNode = childNode.parentNode; + + } + + let parentFirstLevelBlock = childNode.closest(`.${Block.CSS.wrapper}`); + + if (parentFirstLevelBlock) { + + this.currentNode = parentFirstLevelBlock; + + } else { + + throw new Error('Can not find a Block from this child Node'); + + } + + } + } /** diff --git a/src/components/modules/caret.js b/src/components/modules/caret.js new file mode 100644 index 00000000..e51aefc6 --- /dev/null +++ b/src/components/modules/caret.js @@ -0,0 +1,109 @@ +/** + * @class Caret + * @classdesc Contains methods for working Caret + * + * @typedef {Caret} Caret + */ +export default class Caret extends Module { + + /** + * @constructor + */ + constructor({config}) { + + super({config}); + + } + + /** + * Set Caret to the last Block + * + * If last block is not empty, append another empty block + */ + setToTheLastBlock() { + + let blocks = this.Editor.BlockManager.blocks, + lastBlock; + + if (blocks.length) { + + lastBlock = blocks[blocks.length - 1]; + + } + + /** + * If last block is empty and it is an initialBlock, set to that. + * Otherwise, append new empty block and set to that + */ + if (lastBlock.isEmpty) { + + this.set(lastBlock.html); + + } else { + + this.Editor.BlockManager.insert(this.config.initialBlock); + + } + + + /** + // * 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); + // + // } + // + // } + + } + + /** + * Set caret to the passed Node + * @param {Element} node - content-editable Element + */ + set(node) { + + /** + * @todo add working with Selection + * tmp: work with textContent + */ + + node.textContent += '|'; + + } + + +} \ No newline at end of file diff --git a/src/components/modules/events.js b/src/components/modules/events.js index 31078a2a..bf26c95e 100644 --- a/src/components/modules/events.js +++ b/src/components/modules/events.js @@ -15,9 +15,9 @@ export default class Events extends Module { /** * @constructor */ - constructor(config) { + constructor({config}) { - super(config); + super({config}); this.subscribers = {}; } diff --git a/src/components/modules/renderer.js b/src/components/modules/renderer.js index 0cb41a03..38a209a7 100644 --- a/src/components/modules/renderer.js +++ b/src/components/modules/renderer.js @@ -12,9 +12,9 @@ export default class Renderer extends Module { * @constructor * @param {EditorConfig} config */ - constructor(config) { + constructor({config}) { - super(config); + super({config}); } diff --git a/src/components/modules/sanitizer.js b/src/components/modules/sanitizer.js index 6f9dde2b..b589f1ab 100644 --- a/src/components/modules/sanitizer.js +++ b/src/components/modules/sanitizer.js @@ -43,9 +43,9 @@ export default class Sanitizer extends Module { * * @param {SanitizerConfig} config */ - constructor(config) { + constructor({config}) { - super(config); + super({config}); // default config this.defaultConfig = null; diff --git a/src/components/modules/toolbar.js b/src/components/modules/toolbar.js index ed9dde82..056ddefd 100644 --- a/src/components/modules/toolbar.js +++ b/src/components/modules/toolbar.js @@ -54,9 +54,9 @@ export default class Toolbar extends Module { /** * @constructor */ - constructor(config) { + constructor({config}) { - super(config); + super({config}); this.nodes = { wrapper : null, @@ -65,7 +65,6 @@ export default class Toolbar extends Module { // Content Zone plusButton : null, - toolbox : null, // Actions Zone settingsToggler : null, @@ -77,14 +76,25 @@ export default class Toolbar extends Module { defaultSettings: null, }; - this.CSS = { + } + + /** + * CSS styles + * @return {Object} + * @constructor + */ + static get CSS() { + + return { toolbar: 'ce-toolbar', content: 'ce-toolbar__content', actions: 'ce-toolbar__actions', + toolbarOpened: 'ce-toolbar--opened', + // Content Zone - toolbox: 'ce-toolbar__toolbox', plusButton: 'ce-toolbar__plus', + plusButtonHidden: 'ce-toolbar__plus--hidden', // Actions Zone settingsToggler: 'ce-toolbar__settings-btn', @@ -103,14 +113,14 @@ export default class Toolbar extends Module { */ make() { - this.nodes.wrapper = $.make('div', this.CSS.toolbar); + this.nodes.wrapper = $.make('div', Toolbar.CSS.toolbar); /** * Make Content Zone and Actions Zone */ ['content', 'actions'].forEach( el => { - this.nodes[el] = $.make('div', this.CSS[el]); + this.nodes[el] = $.make('div', Toolbar.CSS[el]); $.append(this.nodes.wrapper, this.nodes[el]); }); @@ -121,12 +131,15 @@ export default class Toolbar extends Module { * - Plus Button * - Toolbox */ - ['plusButton', 'toolbox'].forEach( el => { + this.nodes.plusButton = $.make('div', Toolbar.CSS.plusButton); + $.append(this.nodes.content, this.nodes.plusButton); + this.nodes.plusButton.addEventListener('click', event => this.plusButtonClicked(event), false); - this.nodes[el] = $.make('div', this.CSS[el]); - $.append(this.nodes.content, this.nodes[el]); - }); + /** + * Make a Toolbox + */ + this.Editor.Toolbox.make(); /** * Fill Actions Zone: @@ -134,7 +147,7 @@ export default class Toolbar extends Module { * - Remove Block Button * - Settings Panel */ - this.nodes.settingsToggler = $.make('span', this.CSS.settingsToggler); + this.nodes.settingsToggler = $.make('span', Toolbar.CSS.settingsToggler); this.nodes.removeBlockButton = this.makeRemoveBlockButton(); $.append(this.nodes.actions, [this.nodes.settingsToggler, this.nodes.removeBlockButton]); @@ -158,10 +171,10 @@ export default class Toolbar extends Module { */ makeBlockSettingsPanel() { - this.nodes.settings = $.make('div', this.CSS.settings); + this.nodes.settings = $.make('div', Toolbar.CSS.settings); - this.nodes.pluginSettings = $.make('div', this.CSS.pluginSettings); - this.nodes.defaultSettings = $.make('div', this.CSS.defaultSettings); + this.nodes.pluginSettings = $.make('div', Toolbar.CSS.pluginSettings); + this.nodes.defaultSettings = $.make('div', Toolbar.CSS.defaultSettings); $.append(this.nodes.settings, [this.nodes.pluginSettings, this.nodes.defaultSettings]); $.append(this.nodes.actions, this.nodes.settings); @@ -178,7 +191,83 @@ export default class Toolbar extends Module { * @todo add confirmation panel and handlers * @see {@link settings#makeRemoveBlockButton} */ - return $.make('span', this.CSS.removeBlockButton); + return $.make('span', Toolbar.CSS.removeBlockButton); + + } + + /** + * Move Toolbar to the Current Block + */ + move() { + + /** Close Toolbox when we move toolbar */ + this.Editor.Toolbox.close(); + + let currentNode = this.Editor.BlockManager.currentNode; + + /** + * If no one Block selected as a Current + */ + if (!currentNode) { + + return; + + } + + /** + * @todo Compute dynamically on prepare + * @type {number} + */ + const defaultToolbarHeight = 49; + const defaultOffset = 34; + + var newYCoordinate = currentNode.offsetTop - (defaultToolbarHeight / 2) + defaultOffset; + + this.nodes.wrapper.style.transform = `translate3D(0, ${Math.floor(newYCoordinate)}px, 0)`; + + /** Close trash actions */ + // editor.toolbar.settings.hideRemoveActions(); + + } + + /** + * Open Toolbar with Plus Button + */ + open() { + + this.nodes.wrapper.classList.add(Toolbar.CSS.toolbarOpened); + + } + + /** + * Close the Toolbar + */ + close() { + + this.nodes.wrapper.classList.remove(Toolbar.CSS.toolbarOpened); + + } + + /** + * Plus Button public methods + * @return {{hide: function(): void, show: function(): void}} + */ + get plusButton() { + + return { + hide: () => this.nodes.plusButton.classList.add(Toolbar.CSS.plusButtonHidden), + show: () => this.nodes.plusButton.classList.remove(Toolbar.CSS.plusButtonHidden) + }; + + } + + /** + * Handler for Plus Button + * @param {MouseEvent} event + */ + plusButtonClicked(event) { + + this.Editor.Toolbox.toggle(); } diff --git a/src/components/modules/toolbox.js b/src/components/modules/toolbox.js new file mode 100644 index 00000000..e169c12f --- /dev/null +++ b/src/components/modules/toolbox.js @@ -0,0 +1,223 @@ +/** + * @class Toolbox + * @classdesc Holder for Tools + * + * @typedef {Toolbox} Toolbox + * @property {Boolean} opened - opening state + * @property {Object} nodes - Toolbox nodes + * @property {Object} CSS - CSS class names + * + */ +export default class Toolbox extends Module { + + /** + * @constructor + */ + constructor({config}) { + + super({config}); + + this.nodes = { + toolbox: null, + buttons: [] + }; + + /** + * Opening state + * @type {boolean} + */ + this.opened = false; + + } + + /** + * CSS styles + * @return {{toolbox: string, toolboxButton: string, toolboxOpened: string}} + */ + static get CSS() { + + return { + toolbox: 'ce-toolbox', + toolboxButton: 'ce-toolbox__button', + toolboxOpened: 'ce-toolbox--opened', + }; + + } + + /** + * Makes the Toolbox + */ + make() { + + this.nodes.toolbox = $.make('div', Toolbox.CSS.toolbox); + $.append(this.Editor.Toolbar.nodes.content, this.nodes.toolbox); + + this.addTools(); + + } + + /** + * Iterates available tools and appends them to the Toolbox + */ + addTools() { + + let tools = this.Editor.Tools.toolsAvailable; + + for (let toolName in tools) { + + this.addTool(toolName, tools[toolName]); + + } + + } + + /** + * Append Tool to the Toolbox + * + * @param {string} toolName - tool name + * @param {Tool} tool - tool class + */ + addTool(toolName, tool) { + + if (tool.displayInToolbox && !tool.iconClassName) { + + _.log('Toolbar icon class name is missed. Tool %o skipped', 'warn', toolName); + return; + + } + + /** + * @todo Add checkup for the render method + */ + // if (typeof tool.render !== 'function') { + // + // _.log('render method missed. Tool %o skipped', 'warn', tool); + // return; + // + // } + + /** + * Skip tools that pass 'displayInToolbox=false' + */ + if (!tool.displayInToolbox) { + + return; + + } + + let button = $.make('li', [Toolbox.CSS.toolboxButton, tool.iconClassName], { + title: toolName + }); + + /** + * Save tool's name in the button data-name + */ + button.dataset.name = toolName; + + $.append(this.nodes.toolbox, button); + + this.nodes.toolbox.appendChild(button); + this.nodes.buttons.push(button); + + /** + * @todo add event with module Listeners + */ + // this.Editor.Listeners.add(); + button.addEventListener('click', event => { + + this.buttonClicked(event); + + }, false); + + } + + /** + * Toolbox button click listener + * 1) if block is empty -> replace + * 2) if block is not empty -> add new block below + * + * @param {MouseEvent} event + */ + buttonClicked(event) { + + let toolButton = event.target, + toolName = toolButton.dataset.name, + tool = this.Editor.Tools.toolClasses[toolName]; + + /** + * @type {Block} + */ + let currentBlock = this.Editor.BlockManager.currentBlock; + + /** + * We do replace if: + * - block is empty + * - block is not irreplaceable + * @type {Array} + */ + if (!tool.irreplaceable && currentBlock.isEmpty) { + + this.Editor.BlockManager.replace(toolName); + + } else { + + this.Editor.BlockManager.insert(toolName); + + } + + /** + * @todo set caret to the new block + */ + + // window.setTimeout(function () { + + /** Set caret to current block */ + // editor.caret.setToBlock(currentInputIndex); + + // }, 10); + + /** + * Move toolbar when node is changed + */ + this.Editor.Toolbar.move(); + + } + + /** + * Open Toolbox with Tools + */ + open() { + + this.nodes.toolbox.classList.add(Toolbox.CSS.toolboxOpened); + this.opened = true; + + } + + /** + * Close Toolbox + */ + close() { + + this.nodes.toolbox.classList.remove(Toolbox.CSS.toolboxOpened); + this.opened = false; + + } + + /** + * Close Toolbox + */ + toggle() { + + if (!this.opened) { + + this.open(); + + } else { + + this.close(); + + } + + } + +} \ No newline at end of file diff --git a/src/components/modules/tools.js b/src/components/modules/tools.js index 7c75beb9..00cc738c 100644 --- a/src/components/modules/tools.js +++ b/src/components/modules/tools.js @@ -5,10 +5,9 @@ */ /** - * Load user defined tools - * Tools must contain the following important objects: + * Each Tool must contain the following important objects: * - * @typedef {Object} ToolsConfig + * @typedef {Object} ToolConfig {@link docs/tools.md} * @property {String} iconClassname - this a icon in toolbar * @property {Boolean} displayInToolbox - will be displayed in toolbox. Default value is TRUE * @property {Boolean} enableLineBreaks - inserts new block or break lines. Default value is FALSE @@ -19,15 +18,28 @@ */ /** - * @typedef {Tool} Tool - * @property {String} name - name of this module - * @property {Object[]} toolInstances - list of tool instances - * @property {Tools[]} available - available Tools - * @property {Tools[]} unavailable - unavailable Tools + * @typedef {Function} Tool {@link docs/tools.md} + * @property {Boolean} displayInToolbox - By default, tools won't be added in the Toolbox. Pass true to add. + * @property {String} iconClassName - CSS class name for the Toolbox button + * @property {Boolean} irreplaceable - Toolbox behaviour: replace or add new block below + * @property render + * @property save + * @property settings + * @property validate + * + * @todo update according to current API + * @todo describe Tool in the {@link docs/tools.md} + */ + +/** + * Class properties: + * + * @typedef {Tools} Tools + * @property {Tools[]} toolsAvailable - available Tools + * @property {Tools[]} toolsUnavailable - unavailable Tools * @property {Object} toolsClasses - all classes * @property {EditorConfig} config - Editor config */ - export default class Tools extends Module { /** @@ -51,15 +63,18 @@ export default class Tools extends Module { } /** - * If config wasn't passed by user - * @return {ToolsConfig} + * Static getter for default Tool config fields + * + * @usage Tools.defaultConfig.displayInToolbox + * @return {ToolConfig} */ - get defaultConfig() { + static get defaultConfig() { return { - iconClassName : 'default-icon', + iconClassName : '', displayInToolbox : false, - enableLineBreaks : false + enableLineBreaks : false, + irreplaceable : false }; } @@ -67,21 +82,38 @@ export default class Tools extends Module { /** * @constructor * - * @param {ToolsConfig} config + * @param {EditorConfig} config */ - constructor(config) { + constructor({config}) { - super(config); + super({config}); + /** + * Map {name: Class, ...} where: + * name — block type name in JSON. Got from EditorConfig.tools keys + * @type {Object} + */ this.toolClasses = {}; + + /** + * Available tools list + * {name: Class, ...} + * @type {Object} + */ this.toolsAvailable = {}; + + /** + * Tools that rejected a prepare method + * {name: Class, ... } + * @type {Object} + */ this.toolsUnavailable = {}; } /** * Creates instances via passed or default configuration - * @return {boolean} + * @return {Promise} */ prepare() { @@ -128,7 +160,7 @@ export default class Tools extends Module { /** * Binds prepare function of plugins with user or default config - * @return {Array} list of functions that needs to be fired sequently + * @return {Array} list of functions that needs to be fired sequentially */ getListOfPrepareFunctions() { @@ -147,6 +179,13 @@ export default class Tools extends Module { } }); + } else { + + /** + * If Tool hasn't a prepare method, mark it as available + */ + this.toolsAvailable[toolName] = toolClass; + } } @@ -173,16 +212,6 @@ export default class Tools extends Module { } - /** - * Returns all tools - * @return {Array} - */ - getTools() { - - return this.toolInstances; - - } - /** * Return tool`a instance * @@ -209,4 +238,15 @@ export default class Tools extends Module { } + /** + * Check if passed Tool is an instance of Initial Block Tool + * @param {Tool} tool - Tool to check + * @return {Boolean} + */ + isInitial(tool) { + + return tool instanceof this.available[this.config.initialBlock]; + + } + } \ No newline at end of file diff --git a/src/components/modules/ui.js b/src/components/modules/ui.js index d95d7236..424cf0d5 100644 --- a/src/components/modules/ui.js +++ b/src/components/modules/ui.js @@ -31,10 +31,7 @@ // SETTINGS_ITEM : 'ce-settings__item' // }; -let CSS = { - editorWrapper : 'codex-editor', - editorZone : 'ce-redactor' -}; +import Block from '../block'; /** * @class @@ -54,7 +51,6 @@ let CSS = { * @property {Element} nodes.wrapper - * @property {Element} nodes.redactor - */ - export default class UI extends Module { /** @@ -62,9 +58,9 @@ export default class UI extends Module { * * @param {EditorConfig} config */ - constructor(config) { + constructor({config}) { - super(config); + super({config}); this.nodes = { holder: null, @@ -81,45 +77,19 @@ export default class UI extends Module { */ prepare() { - return new Promise( (resolve, reject) => { - - /** - * Element where we need to append CodeX Editor - * @type {Element} - */ - this.nodes.holder = document.getElementById(this.config.holderId); - - if (!this.nodes.holder) { - - reject(Error("Holder wasn't found by ID: #" + this.config.holderId)); - return; - - } - - /** - * Create and save main UI elements - */ - this.nodes.wrapper = $.make('div', CSS.editorWrapper); - this.nodes.redactor = $.make('div', CSS.editorZone); - - this.nodes.wrapper.appendChild(this.nodes.redactor); - this.nodes.holder.appendChild(this.nodes.wrapper); - + return this.make() /** * Make toolbar */ - this.Editor.Toolbar.make(); + .then(() => this.Editor.Toolbar.make()) /** * Load and append CSS */ - this.loadStyles(); - - resolve(); - - }) - - /** Add toolbox tools */ - // .then(addTools_) + .then(() => this.loadStyles()) + /** + * Bind events for the UI elements + */ + .then(() => this.bindEvents()) /** Make container for inline toolbar */ // .then(makeInlineToolbar_) @@ -143,6 +113,58 @@ export default class UI extends Module { } + /** + * CodeX Editor UI CSS class names + * @return {{editorWrapper: string, editorZone: string, block: string}} + */ + get CSS() { + + return { + editorWrapper : 'codex-editor', + editorZone : 'codex-editor__redactor', + }; + + } + + /** + * Makes CodeX Editor interface + * @return {Promise} + */ + make() { + + return new Promise( (resolve, reject) => { + + /** + * Element where we need to append CodeX Editor + * @type {Element} + */ + this.nodes.holder = document.getElementById(this.config.holderId); + + if (!this.nodes.holder) { + + reject(Error("Holder wasn't found by ID: #" + this.config.holderId)); + return; + + } + + /** + * Create and save main UI elements + */ + this.nodes.wrapper = $.make('div', this.CSS.editorWrapper); + this.nodes.redactor = $.make('div', this.CSS.editorZone); + + this.nodes.wrapper.appendChild(this.nodes.redactor); + this.nodes.holder.appendChild(this.nodes.wrapper); + + resolve(); + + }); + + } + + /** + * Appends CSS + */ loadStyles() { /** @@ -164,6 +186,174 @@ export default class UI extends Module { } + /** + * Bind events on the CodeX Editor interface + */ + bindEvents() { + + /** + * @todo bind events with the Listeners module + */ + this.nodes.redactor.addEventListener('click', event => this.redactorClicked(event), false ); + + } + + /** + * All clicks on the redactor zone + * + * @param {MouseEvent} event + * + * @description + * 1. Save clicked Block as a current {@link BlockManager#currentNode} + * it uses for the following: + * - add CSS modifier for the selected Block + * - on Enter press, we make a new Block under that + * + * 2. Move and show the Toolbar + * + * 3. Set a Caret + * + * 4. By clicks on the Editor's bottom zone: + * - if last Block is empty, set a Caret to this + * - otherwise, add a new empty Block and set a Caret to that + * + * 5. Hide the Inline Toolbar + * + * @see selectClickedBlock + * + */ + redactorClicked(event) { + + let clickedNode = event.target; + + /** + * Select clicked Block as Current + */ + try { + + this.Editor.BlockManager.setCurrentBlockByChildNode(clickedNode); + + /** + * If clicked outside first-level Blocks, set Caret to the last empty Block + */ + + } catch (e) { + + this.Editor.Caret.setToTheLastBlock(); + + } + + + + + /** + * @todo hide the Inline Toolbar + */ + // 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 + */ + this.Editor.Toolbar.move(); + this.Editor.Toolbar.open(); + // + // var inputIsEmpty = !editor.content.currentNode.textContent.trim(), + // currentNodeType = editor.content.currentNode.dataset.tool, + // isInitialType = currentNodeType == editor.settings.initialBlockPlugin; + // + // + + /** + * Hide the Plus Button + * */ + this.Editor.Toolbar.plusButton.hide(); + + /** + * Show the Plus Button if: + * - Block is an initial-block (Text) + * - Block is empty + */ + let isInitialBlock = this.Editor.Tools.isInitial(this.Editor.BlockManager.currentBlock.tool), + isEmptyBlock = this.Editor.BlockManager.currentBlock.isEmpty; + + if (isInitialBlock && isEmptyBlock) { + + this.Editor.Toolbar.plusButton.show(); + + } + + } + } // /** @@ -194,54 +384,6 @@ export default class UI extends Module { // // }; // -// /** -// * @private -// * Append tools passed in editor.tools -// */ -// var addTools_ = function () { -// -// var tool, -// toolName, -// toolButton; -// -// for ( toolName in editor.settings.tools ) { -// -// tool = editor.settings.tools[toolName]; -// -// editor.tools[toolName] = tool; -// -// if (!tool.iconClassname && tool.displayInToolbox) { -// -// editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName); -// continue; -// -// } -// -// if (typeof tool.render != 'function') { -// -// editor.core.log('render method missed. Tool %o skipped', 'warn', toolName); -// continue; -// -// } -// -// if (!tool.displayInToolbox) { -// -// continue; -// -// } else { -// -// /** if tools is for toolbox */ -// toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname); -// -// editor.nodes.toolbox.appendChild(toolButton); -// -// editor.nodes.toolbarButtons[toolName] = toolButton; -// -// } -// -// } -// -// }; // // var addInlineToolbarTools_ = function () { // diff --git a/src/components/polyfills.js b/src/components/polyfills.js new file mode 100644 index 00000000..185d0899 --- /dev/null +++ b/src/components/polyfills.js @@ -0,0 +1,24 @@ +/** + * Element.closest() + * + * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest + */ +if (!Element.prototype.matches) + Element.prototype.matches = Element.prototype.msMatchesSelector || + Element.prototype.webkitMatchesSelector; + +if (!Element.prototype.closest) + Element.prototype.closest = function (s) { + + var el = this; + + if (!document.documentElement.contains(el)) return null; + do { + + if (el.matches(s)) return el; + el = el.parentElement || el.parentNode; + + } while (el !== null); + return null; + + }; diff --git a/src/components/utils.js b/src/components/utils.js index 5400792d..52a691e1 100644 --- a/src/components/utils.js +++ b/src/components/utils.js @@ -3,6 +3,43 @@ */ export default class Util { + /** + * Custom logger + * + * @param {string} msg - message + * @param {string} type - logging type 'log'|'warn'|'error'|'info' + * @param {*} args - argument to log with a message + */ + static log(msg, type, args) { + + type = type || 'log'; + + if (!args) { + + args = msg || 'undefined'; + msg = '[codex-editor]: %o'; + + } else { + + msg = '[codex-editor]: ' + msg; + + } + + try{ + + if ( 'console' in window && window.console[ type ] ) { + + if ( args ) window.console[ type ]( msg, args ); + else window.console[ type ]( msg ); + + } + + } catch(e) { + // do nothing + } + + } + /** * @typedef {Object} ChainData * @property {Object} data - data that will be passed to the success or fallback diff --git a/src/styles/block.css b/src/styles/block.css new file mode 100644 index 00000000..4158720c --- /dev/null +++ b/src/styles/block.css @@ -0,0 +1,12 @@ +.ce-block { + border: 1px dotted #ccc; + margin: 2px 0; + + &--selected { + background-color: var(--bg-light); + } + &__content { + max-width: var(--content-width); + margin: 0 auto; + } +} diff --git a/src/styles/main.css b/src/styles/main.css index fcb4a15f..444061ae 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -1,2 +1,5 @@ @import url('variables.css'); @import url('ui.css'); +@import url('toolbar.css'); +@import url('toolbox.css'); +@import url('block.css'); diff --git a/src/styles/toolbar.css b/src/styles/toolbar.css new file mode 100644 index 00000000..38cc6bdf --- /dev/null +++ b/src/styles/toolbar.css @@ -0,0 +1,44 @@ +.ce-toolbar { + position: absolute; + left: 0; + right: 0; + top: 0; + opacity: 0; + visibility: hidden; + transition: opacity 100ms ease; + will-change: opacity, transform; + + &--opened { + opacity: 1; + visibility: visible; + } + + &__content { + max-width: var(--content-width); + margin: 0 auto; + position: relative; + } + &__plus { + position: absolute; + left: calc(-var(--toolbar-buttons-size) - 10px); + display: inline-block; + background-color: var(--bg-light); + width: var(--toolbar-buttons-size); + height: var(--toolbar-buttons-size); + line-height: 34px; + text-align: center; + border-radius: 50%; + + &::after { + content: '+'; + font-size: 26px; + display: block; + margin-top: -2px; + margin-right: -2px; + } + + &--hidden { + display: none; + } + } +} \ No newline at end of file diff --git a/src/styles/toolbox.css b/src/styles/toolbox.css new file mode 100644 index 00000000..47162e06 --- /dev/null +++ b/src/styles/toolbox.css @@ -0,0 +1,34 @@ +.ce-toolbox { + visibility: hidden; + transition: opacity 100ms ease; + will-change: opacity; + + &--opened { + opacity: 1; + visibility: visible; + } + + &__button { + display: inline-block; + list-style: none; + margin: 0; + background: var(--bg-light); + width: var(--toolbar-buttons-size); + height: var(--toolbar-buttons-size); + border-radius: 30px; + overflow: hidden; + text-align: center; + line-height: var(--toolbar-buttons-size); + + &::before { + content: attr(title); + font-size: 22px; + font-weight: 500; + letter-spacing: 1em; + font-variant-caps: all-small-caps; + padding-left: 11.5px; + margin-top: -1px; + display: inline-block; + } + } +} \ No newline at end of file diff --git a/src/styles/ui.css b/src/styles/ui.css index b9f48b47..cb7d1716 100644 --- a/src/styles/ui.css +++ b/src/styles/ui.css @@ -1,12 +1,17 @@ /** * Editor wrapper */ -.codex-editor{ +.codex-editor { position: relative; border: 1px solid #ccc; padding: 10px; + box-sizing: border-box; .hide { display: none; } + + &__redactor { + padding-bottom: 300px; + } } diff --git a/src/styles/variables.css b/src/styles/variables.css index a626836b..8d5db44a 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -5,4 +5,14 @@ */ --bg-light: #eff2f5; + /** + * Block content width + */ + --content-width: 650px; + + /** + * Toolbar Plus Button and Toolbox buttons height and width + */ + --toolbar-buttons-size: 34px; + } \ No newline at end of file