*
* @return {Element[]}
*/
}, {
key: 'getHigherLevelSiblings',
value: function getHigherLevelSiblings(from, direction) {
var current = from,
siblings = [];
/**
* Find passed node's firs-level parent (in example - blockquote)
*/
while (current.parentNode && current.parentNode.contentEditable !== 'true') {
current = current.parentNode;
}
var sibling = direction === 'left' ? 'previousSibling' : 'nextSibling';
/**
* Find all left/right siblings
*/
while (current[sibling]) {
current = current[sibling];
siblings.push(current);
}
return siblings;
}
/**
* Get's deepest first node and checks if offset is zero
* @return {boolean}
*/
}, {
key: 'isAtStart',
get: function get() {
/**
* Don't handle ranges
*/
if (!_selection2.default.isCollapsed) {
return false;
}
var selection = _selection2.default.get(),
anchorNode = selection.anchorNode,
firstNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.pluginsContent);
/**
* Workaround case when caret in the text like " |Hello!"
* selection.anchorOffset is 1, but real caret visible position is 0
* @type {number}
*/
var firstLetterPosition = anchorNode.textContent.search(/\S/);
if (firstLetterPosition === -1) {
// empty text
firstLetterPosition = 0;
}
/**
* In case of
*
*
<-- first (and deepest) node is
* |adaddad <-- anchor node
*
*/
if ($.isEmpty(firstNode)) {
var leftSiblings = this.getHigherLevelSiblings(anchorNode, 'left'),
nothingAtLeft = leftSiblings.every(function (node) {
return $.isEmpty(node);
});
if (nothingAtLeft && selection.anchorOffset === firstLetterPosition) {
return true;
}
}
return firstNode === null || anchorNode === firstNode && selection.anchorOffset === firstLetterPosition;
}
/**
* Get's deepest last node and checks if offset is last node text length
* @return {boolean}
*/
}, {
key: 'isAtEnd',
get: function get() {
/**
* Don't handle ranges
*/
if (!_selection2.default.isCollapsed) {
return false;
}
var selection = _selection2.default.get(),
anchorNode = selection.anchorNode,
lastNode = $.getDeepestNode(this.Editor.BlockManager.currentBlock.pluginsContent, true);
/**
* In case of
*
* adaddad| <-- anchor node
*
<-- first (and deepest) node is
*
*/
if ($.isEmpty(lastNode)) {
var leftSiblings = this.getHigherLevelSiblings(anchorNode, 'right'),
nothingAtRight = leftSiblings.every(function (node) {
return $.isEmpty(node);
});
if (nothingAtRight && selection.anchorOffset === anchorNode.textContent.length) {
return true;
}
}
return anchorNode === lastNode && selection.anchorOffset === lastNode.textContent.length;
}
}]);
return Caret;
}(Module);
Caret.displayName = 'Caret';
exports.default = Caret;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! dom */ "./src/components/dom.js"), __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/modules/events.js":
/*!******************************************!*\
!*** ./src/components/modules/events.js ***!
\******************************************/
/*! no static exports found */
/***/ (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; }
/**
* @module eventDispatcher
*
* Has two important methods:
* - {Function} on - appends subscriber to the event. If event doesn't exist - creates new one
* - {Function} emit - fires all subscribers with data
* - {Function off - unsubsribes callback
*
* @version 1.0.0
*
* @typedef {Events} Events
* @property {Object} subscribers - all subscribers grouped by event name
*/
var Events = function (_Module) {
_inherits(Events, _Module);
/**
* @constructor
*/
function Events(_ref) {
var config = _ref.config;
_classCallCheck(this, Events);
var _this = _possibleConstructorReturn(this, (Events.__proto__ || Object.getPrototypeOf(Events)).call(this, { config: config }));
_this.subscribers = {};
return _this;
}
/**
* Subscribe any event on callback
*
* @param {String} eventName - event name
* @param {Function} callback - subscriber
*/
_createClass(Events, [{
key: "on",
value: function on(eventName, callback) {
if (!(eventName in this.subscribers)) {
this.subscribers[eventName] = [];
}
// group by events
this.subscribers[eventName].push(callback);
}
/**
* Emit callbacks with passed data
*
* @param {String} eventName - event name
* @param {Object} data - subscribers get this data when they were fired
*/
}, {
key: "emit",
value: function emit(eventName, data) {
if (!this.subscribers[eventName]) {
return;
}
this.subscribers[eventName].reduce(function (previousData, currentHandler) {
var newData = currentHandler(previousData);
return newData ? newData : previousData;
}, data);
}
/**
* Unsubsribe callback from event
*
* @param eventName
* @param callback
*/
}, {
key: "off",
value: function off(eventName, callback) {
for (var i = 0; i < this.subscribers[eventName].length; i++) {
if (this.subscribers[eventName][i] === callback) {
delete this.subscribers[eventName][i];
break;
}
}
}
/**
* Destroyer
* clears subsribers list
*/
}, {
key: "destroy",
value: function destroy() {
this.subscribers = null;
}
}]);
return Events;
}(Module);
Events.displayName = "Events";
exports.default = Events;
module.exports = exports["default"];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts")))
/***/ }),
/***/ "./src/components/modules/keyboard.js":
/*!********************************************!*\
!*** ./src/components/modules/keyboard.js ***!
\********************************************/
/*! no static exports found */
/***/ (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 Keyboard
* @classdesc Сlass to handle the keydowns
*
* @author CodeX Team (team@ifmo.su)
* @copyright CodeX Team 2017
* @license The MIT License (MIT)
* @version 1.0.0
*/
/**
* @typedef {Keyboard} Keyboard
*/
var Keyboard = function (_Module) {
_inherits(Keyboard, _Module);
/**
* @constructor
*/
function Keyboard(_ref) {
var config = _ref.config;
_classCallCheck(this, Keyboard);
return _possibleConstructorReturn(this, (Keyboard.__proto__ || Object.getPrototypeOf(Keyboard)).call(this, { config: config }));
}
/**
* Handler on Block for keyboard keys at keydown event
*
* @param {KeyboardEvent} event
*/
_createClass(Keyboard, [{
key: 'blockKeydownsListener',
value: function blockKeydownsListener(event) {
switch (event.keyCode) {
case _.keyCodes.BACKSPACE:
_.log('Backspace key pressed');
this.backspacePressed(event);
break;
case _.keyCodes.ENTER:
_.log('Enter key pressed');
this.enterPressed(event);
break;
case _.keyCodes.DOWN:
case _.keyCodes.RIGHT:
_.log('Right/Down key pressed');
this.arrowRightAndDownPressed();
break;
case _.keyCodes.UP:
case _.keyCodes.LEFT:
_.log('Left/Up key pressed');
this.arrowLeftAndUpPressed();
break;
default:
break;
}
}
/**
* Handle pressing enter key
*
* @param {KeyboardEvent} event
*/
}, {
key: 'enterPressed',
value: function enterPressed(event) {
var currentBlock = this.Editor.BlockManager.currentBlock,
toolsConfig = this.config.toolsConfig[currentBlock.name];
/**
* Don't handle Enter keydowns when Tool sets enableLineBreaks to true.
* Uses for Tools like where line breaks should be handled by default behaviour.
*/
if (toolsConfig && toolsConfig[this.Editor.Tools.apiSettings.IS_ENABLED_LINE_BREAKS]) {
return;
}
/**
* Allow to create linebreaks by Shift+Enter
*/
if (event.shiftKey) {
return;
}
/**
* Split the Current Block into two blocks
*/
this.Editor.BlockManager.split();
/**
* Renew local current node after split
*/
var newCurrent = this.Editor.BlockManager.currentBlock;
this.Editor.Toolbar.move();
this.Editor.Toolbar.open();
if (this.Editor.Tools.isInitial(newCurrent.tool) && newCurrent.isEmpty) {
this.Editor.Toolbar.plusButton.show();
}
event.preventDefault();
}
/**
* Handle backspace keypress on block
* @param {KeyboardEvent} event - keydown
*/
}, {
key: 'backspacePressed',
value: function backspacePressed(event) {
var _this2 = this;
var BM = this.Editor.BlockManager;
var isFirstBlock = BM.currentBlockIndex === 0,
canMergeBlocks = this.Editor.Caret.isAtStart && !isFirstBlock;
if (!canMergeBlocks) {
return;
}
// preventing browser default behaviour
event.preventDefault();
var targetBlock = BM.getBlockByIndex(BM.currentBlockIndex - 1),
blockToMerge = BM.currentBlock;
/**
* Blocks that can be merged:
* 1) with the same Name
* 2) Tool has 'merge' method
*
* other case will handle as usual ARROW LEFT behaviour
*/
if (blockToMerge.name !== targetBlock.name || !targetBlock.mergeable) {
BM.navigatePrevious();
}
var setCaretToTheEnd = !targetBlock.isEmpty ? true : false;
BM.mergeBlocks(targetBlock, blockToMerge).then(function () {
window.setTimeout(function () {
// set caret to the block without offset at the end
_this2.Editor.Caret.setToBlock(BM.currentBlock, 0, setCaretToTheEnd);
_this2.Editor.Toolbar.close();
}, 10);
});
}
/**
* Handle right and down keyboard keys
*/
}, {
key: 'arrowRightAndDownPressed',
value: function arrowRightAndDownPressed() {
this.Editor.BlockManager.navigateNext();
}
/**
* Handle left and up keyboard keys
*/
}, {
key: 'arrowLeftAndUpPressed',
value: function arrowLeftAndUpPressed() {
this.Editor.BlockManager.navigatePrevious();
}
}]);
return Keyboard;
}(Module);
Keyboard.displayName = 'Keyboard';
exports.default = Keyboard;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/modules/listeners.js":
/*!*********************************************!*\
!*** ./src/components/modules/listeners.js ***!
\*********************************************/
/*! no static exports found */
/***/ (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 Editor Listeners module
*
* @module Listeners
*
* Module-decorator for event listeners assignment
*
* @author Codex Team
* @version 2.0.0
*/
/**
* @typedef {Listeners} Listeners
* @property {Array} allListeners
*/
var Listeners = function (_Module) {
_inherits(Listeners, _Module);
/**
* @constructor
* @param {EditorConfig} config
*/
function Listeners(_ref) {
var config = _ref.config;
_classCallCheck(this, Listeners);
var _this = _possibleConstructorReturn(this, (Listeners.__proto__ || Object.getPrototypeOf(Listeners)).call(this, { config: config }));
_this.allListeners = [];
return _this;
}
/**
* Assigns event listener on element
*
* @param {Element} element - DOM element that needs to be listened
* @param {String} eventType - event type
* @param {Function} handler - method that will be fired on event
* @param {Boolean} useCapture - use event bubbling
*/
_createClass(Listeners, [{
key: "on",
value: function on(element, eventType, handler) {
var useCapture = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var assignedEventData = {
element: element,
eventType: eventType,
handler: handler,
useCapture: useCapture
};
var alreadyExist = this.findOne(element, eventType, handler);
if (alreadyExist) return;
this.allListeners.push(assignedEventData);
element.addEventListener(eventType, handler, useCapture);
}
/**
* Removes event listener from element
*
* @param {Element} element - DOM element that we removing listener
* @param {String} eventType - event type
* @param {Function} handler - remove handler, if element listens several handlers on the same event type
* @param {Boolean} useCapture - use event bubbling
*/
}, {
key: "off",
value: function off(element, eventType, handler) {
var useCapture = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var existingListeners = this.findAll(element, eventType, handler);
for (var i = 0; i < existingListeners.length; i++) {
var index = this.allListeners.indexOf(existingListeners[i]);
if (index > 0) {
this.allListeners.splice(index, 1);
}
}
element.removeEventListener(eventType, handler, useCapture);
}
/**
* Search method: looks for listener by passed element
* @param {Element} element - searching element
* @returns {Array} listeners that found on element
*/
}, {
key: "findByElement",
value: function findByElement(element) {
var listenersOnElement = [];
for (var i = 0; i < this.allListeners.length; i++) {
var listener = this.allListeners[i];
if (listener.element === element) {
listenersOnElement.push(listener);
}
}
return listenersOnElement;
}
/**
* Search method: looks for listener by passed event type
* @param {String} eventType
* @return {Array} listeners that found on element
*/
}, {
key: "findByType",
value: function findByType(eventType) {
var listenersWithType = [];
for (var i = 0; i < this.allListeners.length; i++) {
var listener = this.allListeners[i];
if (listener.type === eventType) {
listenersWithType.push(listener);
}
}
return listenersWithType;
}
/**
* Search method: looks for listener by passed handler
* @param {Function} handler
* @return {Array} listeners that found on element
*/
}, {
key: "findByHandler",
value: function findByHandler(handler) {
var listenersWithHandler = [];
for (var i = 0; i < this.allListeners.length; i++) {
var listener = this.allListeners[i];
if (listener.handler === handler) {
listenersWithHandler.push(listener);
}
}
return listenersWithHandler;
}
/**
* @param {Element} element
* @param {String} eventType
* @param {Function} handler
* @return {Element|null}
*/
}, {
key: "findOne",
value: function findOne(element, eventType, handler) {
var foundListeners = this.findAll(element, eventType, handler);
return foundListeners.length > 0 ? foundListeners[0] : null;
}
/**
* @param {Element} element
* @param {String} eventType
* @param {Function} handler
* @return {Array}
*/
}, {
key: "findAll",
value: function findAll(element, eventType, handler) {
var found = void 0,
foundByElements = element ? this.findByElement(element) : [];
// foundByEventType = eventType ? this.findByType(eventType) : [],
// foundByHandler = handler ? this.findByHandler(handler) : [];
if (element && eventType && handler) {
found = foundByElements.filter(function (event) {
return event.eventType === eventType && event.handler === handler;
});
} else if (element && eventType) {
found = foundByElements.filter(function (event) {
return event.eventType === eventType;
});
} else {
found = foundByElements;
}
return found;
}
/**
* Removes all listeners
*/
}, {
key: "removeAll",
value: function removeAll() {
this.allListeners.map(function (current) {
current.element.removeEventListener(current.eventType, current.handler);
});
this.allListeners = [];
}
}]);
return Listeners;
}(Module);
Listeners.displayName = "Listeners";
exports.default = Listeners;
module.exports = exports["default"];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts")))
/***/ }),
/***/ "./src/components/modules/renderer.js":
/*!********************************************!*\
!*** ./src/components/modules/renderer.js ***!
\********************************************/
/*! no static exports found */
/***/ (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 Editor Renderer Module
*
* @module Renderer
* @author CodeX Team
*
* @version 2.0.0
*/
var Renderer = function (_Module) {
_inherits(Renderer, _Module);
/**
* @constructor
* @param {EditorConfig} config
*/
function Renderer(_ref) {
var config = _ref.config;
_classCallCheck(this, Renderer);
return _possibleConstructorReturn(this, (Renderer.__proto__ || Object.getPrototypeOf(Renderer)).call(this, { config: config }));
}
/**
* @typedef {Object} RendererItems
* @property {String} type - tool name
* @property {Object} data - tool data
*/
/**
* @example
*
* items: [
* {
* type : 'paragraph',
* data : {
* text : 'Hello from Codex!'
* }
* },
* {
* type : 'paragraph',
* data : {
* text : 'Leave feedback if you like it!'
* }
* },
* ]
*
*/
/**
* Make plugin blocks from array of plugin`s data
* @param {RendererItems[]} items
*/
_createClass(Renderer, [{
key: "render",
value: function render(items) {
var _this2 = this;
var chainData = [];
var _loop = function _loop(i) {
chainData.push({
function: function _function() {
return _this2.insertBlock(items[i]);
}
});
};
for (var i = 0; i < items.length; i++) {
_loop(i);
}
return _.sequence(chainData);
}
/**
* Get plugin instance
* Add plugin instance to BlockManager
* Insert block to working zone
*
* @param {Object} item
* @returns {Promise.}
* @private
*/
}, {
key: "insertBlock",
value: function insertBlock(item) {
var tool = item.type,
data = item.data,
settings = item.settings;
this.Editor.BlockManager.insert(tool, data, settings);
return Promise.resolve();
}
}]);
return Renderer;
}(Module);
Renderer.displayName = "Renderer";
exports.default = Renderer;
module.exports = exports["default"];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/modules/sanitizer.js":
/*!*********************************************!*\
!*** ./src/components/modules/sanitizer.js ***!
\*********************************************/
/*! no static exports found */
/***/ (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(_ref) {
var config = _ref.config;
_classCallCheck(this, Sanitizer);
// default config
var _this = _possibleConstructorReturn(this, (Sanitizer.__proto__ || Object.getPrototypeOf(Sanitizer)).call(this, { config: config }));
_this.defaultConfig = null;
_this._sanitizerInstance = null;
/** Custom configuration */
_this.sanitizerConfig = config.settings ? config.settings.sanitizer : {};
/** HTML Janitor library */
_this.sanitizerInstance = __webpack_require__(/*! html-janitor */ "./node_modules/html-janitor/src/html-janitor.js");
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
* @param {Object} customConfig - custom sanitizer configuration. Method uses default if param is empty
* @return {String} clean HTML
*/
value: function clean(taintString) {
var customConfig = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
if (_.isEmpty(customConfig)) {
return this._sanitizerInstance.clean(taintString);
} else {
return Sanitizer.clean(taintString, customConfig);
}
}
/**
* 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(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/modules/saver.js":
/*!*****************************************!*\
!*** ./src/components/modules/saver.js ***!
\*****************************************/
/*! no static exports found */
/***/ (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 Editor Saver
*
* @module Saver
* @author Codex Team
* @version 2.0.0
*/
/**
* @typedef {Object} SavedData
* @property {Date} time - saving proccess time
* @property {Object} items - extracted data
* @property {String} version - CodexEditor version
*/
/**
* @classdesc This method reduces all Blocks asyncronically and calls Block's save method to extract data
*
* @typedef {Saver} Saver
* @property {Element} html - Editor HTML content
* @property {String} json - Editor JSON output
*/
var Saver = function (_Module) {
_inherits(Saver, _Module);
/**
* @constructor
* @param config
*/
function Saver(_ref) {
var config = _ref.config;
_classCallCheck(this, Saver);
var _this = _possibleConstructorReturn(this, (Saver.__proto__ || Object.getPrototypeOf(Saver)).call(this, { config: config }));
_this.output = null;
_this.blocksData = [];
return _this;
}
/**
* Composes new chain of Promises to fire them alternatelly
* @return {SavedData}
*/
_createClass(Saver, [{
key: 'save',
value: function save() {
var _this2 = this;
var blocks = this.Editor.BlockManager.blocks,
chainData = [];
blocks.forEach(function (block) {
chainData.push(block.data);
});
return Promise.all(chainData).then(function (allExtractedData) {
return _this2.makeOutput(allExtractedData);
}).then(function (outputData) {
return outputData;
});
}
/**
* Creates output object with saved data, time and version of editor
* @param {Object} allExtractedData
* @return {SavedData}
*/
}, {
key: 'makeOutput',
value: function makeOutput(allExtractedData) {
var items = [],
totalTime = 0;
console.groupCollapsed('[CodexEditor saving]:');
allExtractedData.forEach(function (extraction) {
/** Group process info */
console.log('\xAB' + extraction.tool + '\xBB saving info', extraction);
totalTime += extraction.time;
items.push(extraction.data);
});
console.log('Total', totalTime);
console.groupEnd();
return {
time: +new Date(),
items: items,
version: "2.0.0"
};
}
}]);
return Saver;
}(Module);
// module.exports = (function (saver) {
//
// let editor = codex.editor;
//
// /**
// * @public
// * Save blocks
// */
// saver.save = function () {
//
// /** Save html content of redactor to memory */
// editor.state.html = editor.nodes.redactor.innerHTML;
//
// /** Clean jsonOutput state */
// editor.state.jsonOutput = [];
//
// return saveBlocks(editor.nodes.redactor.childNodes);
//
// };
//
// /**
// * @private
// * Save each block data
// *
// * @param blocks
// * @returns {Promise.}
// */
// let saveBlocks = function (blocks) {
//
// let data = [];
//
// for(let index = 0; index < blocks.length; index++) {
//
// data.push(getBlockData(blocks[index]));
//
// }
//
// return Promise.all(data)
// .then(makeOutput)
// .catch(editor.core.log);
//
// };
//
// /** Save and validate block data */
// let getBlockData = function (block) {
//
// return saveBlockData(block)
// .then(validateBlockData)
// .catch(editor.core.log);
//
// };
//
// /**
// * @private
// * Call block`s plugin save method and return saved data
// *
// * @param block
// * @returns {Object}
// */
// let saveBlockData = function (block) {
//
// let pluginName = block.dataset.tool;
//
// /** Check for plugin existence */
// if (!editor.tools[pluginName]) {
//
// editor.core.log(`Plugin «${pluginName}» not found`, 'error');
// return {data: null, pluginName: null};
//
// }
//
// /** Check for plugin having save method */
// if (typeof editor.tools[pluginName].save !== 'function') {
//
// editor.core.log(`Plugin «${pluginName}» must have save method`, 'error');
// return {data: null, pluginName: null};
//
// }
//
// /** Result saver */
// let blockContent = block.childNodes[0],
// pluginsContent = blockContent.childNodes[0],
// position = pluginsContent.dataset.inputPosition;
//
// /** If plugin wasn't available then return data from cache */
// if ( editor.tools[pluginName].available === false ) {
//
// return Promise.resolve({data: codex.editor.state.blocks.items[position].data, pluginName});
//
// }
//
// return Promise.resolve(pluginsContent)
// .then(editor.tools[pluginName].save)
// .then(data => Object({data, pluginName}));
//
// };
//
// /**
// * Call plugin`s validate method. Return false if validation failed
// *
// * @param data
// * @param pluginName
// * @returns {Object|Boolean}
// */
// let validateBlockData = function ({data, pluginName}) {
//
// if (!data || !pluginName) {
//
// return false;
//
// }
//
// if (editor.tools[pluginName].validate) {
//
// let result = editor.tools[pluginName].validate(data);
//
// /**
// * Do not allow invalid data
// */
// if (!result) {
//
// return false;
//
// }
//
// }
//
// return {data, pluginName};
//
//
// };
//
// /**
// * Compile article output
// *
// * @param savedData
// * @returns {{time: number, version, items: (*|Array)}}
// */
// let makeOutput = function (savedData) {
//
// savedData = savedData.filter(blockData => blockData);
//
// let items = savedData.map(blockData => Object({type: blockData.pluginName, data: blockData.data}));
//
// editor.state.jsonOutput = items;
//
// return {
// id: editor.state.blocks.id || null,
// time: +new Date(),
// version: editor.version,
// items
// };
//
// };
//
// return saver;
//
// })({});
Saver.displayName = 'Saver';
exports.default = Saver;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts")))
/***/ }),
/***/ "./src/components/modules/toolbar-blockSettings.js":
/*!*********************************************************!*\
!*** ./src/components/modules/toolbar-blockSettings.js ***!
\*********************************************************/
/*! no static exports found */
/***/ (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; }
/**
* Block Settings
*
* ____ Settings Panel ____
* | ...................... |
* | . Tool Settings . |
* | ...................... |
* | . Default Settings . |
* | ...................... |
* |________________________|
*/
var BlockSettings = function (_Module) {
_inherits(BlockSettings, _Module);
/**
* @constructor
*/
function BlockSettings(_ref) {
var config = _ref.config;
_classCallCheck(this, BlockSettings);
var _this = _possibleConstructorReturn(this, (BlockSettings.__proto__ || Object.getPrototypeOf(BlockSettings)).call(this, { config: config }));
_this.nodes = {
wrapper: null,
toolSettings: null,
defaultSettings: null
};
return _this;
}
/**
* Module Events
* @return {{opened: string, closed: string}}
*/
_createClass(BlockSettings, [{
key: 'make',
/**
* Panel with block settings with 2 sections:
* - Tool's Settings
* - Default Settings [Move, Remove, etc]
*
* @return {Element}
*/
value: function make() {
this.nodes.wrapper = $.make('div', BlockSettings.CSS.wrapper);
this.nodes.toolSettings = $.make('div', BlockSettings.CSS.toolSettings);
this.nodes.defaultSettings = $.make('div', BlockSettings.CSS.defaultSettings);
$.append(this.nodes.wrapper, [this.nodes.toolSettings, this.nodes.defaultSettings]);
}
/**
* Add Tool's settings
*/
}, {
key: 'addToolSettings',
value: function addToolSettings() {
if (typeof this.Editor.BlockManager.currentBlock.tool.makeSettings === 'function') {
$.append(this.nodes.toolSettings, this.Editor.BlockManager.currentBlock.tool.makeSettings());
}
}
/**
* Add default settings
*/
}, {
key: 'addDefaultSettings',
value: function addDefaultSettings() {
$.append(this.nodes.defaultSettings, this.Editor.BlockManager.currentBlock.renderTunes());
}
/**
* Is Block Settings opened or not
* @returns {boolean}
*/
}, {
key: 'open',
/**
* Open Block Settings pane
*/
value: function open() {
this.nodes.wrapper.classList.add(BlockSettings.CSS.wrapperOpened);
/**
* Fill Tool's settings
*/
this.addToolSettings();
/**
* Add default settings that presents for all Blocks
*/
this.addDefaultSettings();
/** Tell to subscribers that block settings is opened */
this.Editor.Events.emit(this.events.opened);
}
/**
* Close Block Settings pane
*/
}, {
key: 'close',
value: function close() {
this.nodes.wrapper.classList.remove(BlockSettings.CSS.wrapperOpened);
/** Clear settings */
this.nodes.toolSettings.innerHTML = '';
this.nodes.defaultSettings.innerHTML = '';
/** Tell to subscribers that block settings is closed */
this.Editor.Events.emit(this.events.closed);
}
}, {
key: 'events',
get: function get() {
return {
opened: 'block-settings-opened',
closed: 'block-settings-closed'
};
}
/**
* Block Settings CSS
* @return {{wrapper, wrapperOpened, toolSettings, defaultSettings, button}}
*/
}, {
key: 'opened',
get: function get() {
return this.nodes.wrapper.classList.contains(BlockSettings.CSS.wrapperOpened);
}
}], [{
key: 'CSS',
get: function get() {
return {
// Settings Panel
wrapper: 'ce-settings',
wrapperOpened: 'ce-settings--opened',
toolSettings: 'ce-settings__plugin-zone',
defaultSettings: 'ce-settings__default-zone',
button: 'ce-settings__button'
};
}
}]);
return BlockSettings;
}(Module);
BlockSettings.displayName = 'BlockSettings';
exports.default = BlockSettings;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! dom */ "./src/components/dom.js")))
/***/ }),
/***/ "./src/components/modules/toolbar-inline.ts":
/*!**************************************************!*\
!*** ./src/components/modules/toolbar-inline.ts ***!
\**************************************************/
/*! no static exports found */
/***/ (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; }; }();
var _inlineToolBold = __webpack_require__(/*! ../inline-tools/inline-tool-bold */ "./src/components/inline-tools/inline-tool-bold.ts");
var _inlineToolBold2 = _interopRequireDefault(_inlineToolBold);
var _inlineToolItalic = __webpack_require__(/*! ../inline-tools/inline-tool-italic */ "./src/components/inline-tools/inline-tool-italic.ts");
var _inlineToolItalic2 = _interopRequireDefault(_inlineToolItalic);
var _inlineToolLink = __webpack_require__(/*! ../inline-tools/inline-tool-link */ "./src/components/inline-tools/inline-tool-link.ts");
var _inlineToolLink2 = _interopRequireDefault(_inlineToolLink);
var _selection = __webpack_require__(/*! ../selection */ "./src/components/selection.js");
var _selection2 = _interopRequireDefault(_selection);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
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; }
var InlineToolbar = function (_Module) {
_inherits(InlineToolbar, _Module);
/**
* @constructor
*/
function InlineToolbar(_ref) {
var config = _ref.config;
_classCallCheck(this, InlineToolbar);
/**
* Inline Toolbar elements
*/
var _this = _possibleConstructorReturn(this, (InlineToolbar.__proto__ || Object.getPrototypeOf(InlineToolbar)).call(this, { config: config }));
_this.nodes = {
wrapper: null,
buttons: null,
/**
* Zone below the buttons where Tools can create additional actions by 'renderActions()' method
* For example, input for the 'link' tool or textarea for the 'comment' tool
*/
actions: null
};
/**
* CSS styles
*/
_this.CSS = {
inlineToolbar: 'ce-inline-toolbar',
inlineToolbarShowed: 'ce-inline-toolbar--showed',
buttonsWrapper: 'ce-inline-toolbar__buttons',
actionsWrapper: 'ce-inline-toolbar__actions'
};
/**
* Margin above/below the Toolbar
*/
_this.toolbarVerticalMargin = 20;
return _this;
}
/**
* Inline Toolbar Tools
* @todo Merge internal tools with external
*/
_createClass(InlineToolbar, [{
key: 'make',
/**
* Making DOM
*/
value: function make() {
this.nodes.wrapper = $.make('div', this.CSS.inlineToolbar);
this.nodes.buttons = $.make('div', this.CSS.buttonsWrapper);
this.nodes.actions = $.make('div', this.CSS.actionsWrapper);
/**
* Append Inline Toolbar to the Editor
*/
$.append(this.nodes.wrapper, [this.nodes.buttons, this.nodes.actions]);
$.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);
/**
* Append Inline Toolbar Tools
*/
this.addTools();
}
/**
*
*
* Moving / appearance
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
/**
* Shows Inline Toolbar by keyup/mouseup
* @param {KeyboardEvent|MouseEvent} event
*/
}, {
key: 'handleShowingEvent',
value: function handleShowingEvent(event) {
if (!this.allowedToShow(event)) {
this.close();
return;
}
this.move();
this.open();
/** Check Tools state for selected fragment */
this.checkToolsState();
}
/**
* Move Toolbar to the selected text
*/
}, {
key: 'move',
value: function move() {
var selectionRect = _selection2.default.rect;
var wrapperOffset = this.Editor.UI.nodes.wrapper.getBoundingClientRect();
var newCoords = {
x: selectionRect.x - wrapperOffset.left,
y: selectionRect.y + selectionRect.height
// + window.scrollY
- wrapperOffset.top + this.toolbarVerticalMargin
};
/**
* If we know selections width, place InlineToolbar to center
*/
if (selectionRect.width) {
newCoords.x += Math.floor(selectionRect.width / 2);
}
this.nodes.wrapper.style.left = Math.floor(newCoords.x) + 'px';
this.nodes.wrapper.style.top = Math.floor(newCoords.y) + 'px';
}
/**
* Shows Inline Toolbar
*/
}, {
key: 'open',
value: function open() {
this.nodes.wrapper.classList.add(this.CSS.inlineToolbarShowed);
this.tools.forEach(function (tool) {
if (typeof tool.clear === 'function') {
tool.clear();
}
});
}
/**
* Hides Inline Toolbar
*/
}, {
key: 'close',
value: function close() {
this.nodes.wrapper.classList.remove(this.CSS.inlineToolbarShowed);
this.tools.forEach(function (tool) {
if (typeof tool.clear === 'function') {
tool.clear();
}
});
}
/**
* Need to show Inline Toolbar or not
* @param {KeyboardEvent|MouseEvent} event
*/
}, {
key: 'allowedToShow',
value: function allowedToShow(event) {
/**
* Tags conflicts with window.selection function.
* Ex. IMG tag returns null (Firefox) or Redactors wrapper (Chrome)
*/
var tagsConflictsWithSelection = ['IMG', 'INPUT'];
if (event && tagsConflictsWithSelection.includes(event.target.tagName)) {
return false;
}
var currentSelection = _selection2.default.get(),
selectedText = _selection2.default.text;
// old browsers
if (!currentSelection || !currentSelection.anchorNode) {
return false;
}
// empty selection
if (currentSelection.isCollapsed || selectedText.length < 1) {
return false;
}
// is enabled by current Block's Tool
var currentBlock = this.Editor.BlockManager.getBlock(currentSelection.anchorNode);
if (!currentBlock) {
return false;
}
var toolConfig = this.config.toolsConfig[currentBlock.name];
return toolConfig && toolConfig[this.Editor.Tools.apiSettings.IS_ENABLED_INLINE_TOOLBAR];
}
/**
*
*
* Working with Tools
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
/**
* Fill Inline Toolbar with Tools
*/
}, {
key: 'addTools',
value: function addTools() {
var _this2 = this;
this.tools.forEach(function (tool) {
_this2.addTool(tool);
});
}
/**
* Add tool button and activate clicks
* @param {InlineTool} tool - Tool's instance
*/
}, {
key: 'addTool',
value: function addTool(tool) {
var _this3 = this;
var button = tool.render();
if (!button) {
_.log('Render method must return an instance of Node', 'warn', tool);
return;
}
this.nodes.buttons.appendChild(button);
if (typeof tool.renderActions === 'function') {
var actions = tool.renderActions();
this.nodes.actions.appendChild(actions);
}
this.Editor.Listeners.on(button, 'click', function () {
_this3.toolClicked(tool);
});
}
/**
* Inline Tool button clicks
* @param {InlineTool} tool - Tool's instance
*/
}, {
key: 'toolClicked',
value: function toolClicked(tool) {
var range = _selection2.default.range;
tool.surround(range);
this.checkToolsState();
}
/**
* Check Tools` state by selection
*/
}, {
key: 'checkToolsState',
value: function checkToolsState() {
this.tools.forEach(function (tool) {
tool.checkState(_selection2.default.get());
});
}
}, {
key: 'tools',
get: function get() {
var _this4 = this;
if (!this.toolsInstances) {
this.toolsInstances = [new _inlineToolBold2.default(this.Editor.API.methods), new _inlineToolItalic2.default(this.Editor.API.methods), new _inlineToolLink2.default(this.Editor.API.methods)].concat(_toConsumableArray(this.Editor.Tools.inline.map(function (Tool) {
return new Tool(_this4.Editor.API.methods);
})));
}
return this.toolsInstances;
}
}]);
return InlineToolbar;
}(Module);
InlineToolbar.displayName = 'InlineToolbar';
exports.default = InlineToolbar;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! dom */ "./src/components/dom.js"), __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/modules/toolbar-toolbox.js":
/*!***************************************************!*\
!*** ./src/components/modules/toolbar-toolbox.js ***!
\***************************************************/
/*! no static exports found */
/***/ (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;
var api = this.Editor.Tools.apiSettings;
if (tool[api.IS_DISPLAYED_IN_TOOLBOX] && !tool[api.TOOLBAR_ICON_CLASS]) {
_.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[api.IS_DISPLAYED_IN_TOOLBOX]) {
return;
}
var button = $.make('li', [Toolbox.CSS.toolboxButton, tool[api.TOOLBAR_ICON_CLASS]], {
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[this.Editor.Tools.apiSettings.IS_IRREPLACEBLE_TOOL] && 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(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! dom */ "./src/components/dom.js"), __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/modules/toolbar.js":
/*!*******************************************!*\
!*** ./src/components/modules/toolbar.js ***!
\*******************************************/
/*! no static exports found */
/***/ (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; }
/**
*
* «Toolbar» is the node that moves up/down over current block
*
* ______________________________________ Toolbar ____________________________________________
* | |
* | ..................... Content .................... ......... Block Actions .......... |
* | . . . . |
* | . . . [Open Settings] . |
* | . [Plus Button] [Toolbox: {Tool1}, {Tool2}] . . . |
* | . . . [Settings Panel] . |
* | .................................................. .................................. |
* | |
* |___________________________________________________________________________________________|
*
*
* Toolbox — its an Element contains tools buttons. Can be shown by Plus Button.
*
* _______________ Toolbox _______________
* | |
* | [Header] [Image] [List] [Quote] ... |
* |_______________________________________|
*
*
* Settings Panel — is an Element with block settings:
*
* ____ Settings Panel ____
* | ...................... |
* | . Tool Settings . |
* | ...................... |
* | . Default Settings . |
* | ...................... |
* |________________________|
*
*
* @class
* @classdesc Toolbar module
*
* @typedef {Toolbar} Toolbar
* @property {Object} nodes
* @property {Element} nodes.wrapper - Toolbar main element
* @property {Element} nodes.content - Zone with Plus button and toolbox.
* @property {Element} nodes.actions - Zone with Block Settings and Remove Button
* @property {Element} nodes.blockActionsButtons - Zone with Block Buttons: [Settings]
* @property {Element} nodes.plusButton - Button that opens or closes Toolbox
* @property {Element} nodes.toolbox - Container for tools
* @property {Element} nodes.settingsToggler - open/close Settings Panel button
* @property {Element} nodes.settings - Settings Panel
* @property {Element} nodes.pluginSettings - Plugin Settings section of Settings Panel
* @property {Element} nodes.defaultSettings - Default Settings section of Settings Panel
*/
var Toolbar = function (_Module) {
_inherits(Toolbar, _Module);
/**
* @constructor
*/
function Toolbar(_ref) {
var config = _ref.config;
_classCallCheck(this, Toolbar);
var _this = _possibleConstructorReturn(this, (Toolbar.__proto__ || Object.getPrototypeOf(Toolbar)).call(this, { config: config }));
_this.nodes = {
wrapper: null,
content: null,
actions: null,
// Content Zone
plusButton: null,
// Actions Zone
blockActionsButtons: null,
settingsToggler: null
};
return _this;
}
/**
* CSS styles
* @return {Object}
* @constructor
*/
_createClass(Toolbar, [{
key: 'make',
/**
* Makes toolbar
*/
value: function make() {
var _this2 = this;
this.nodes.wrapper = $.make('div', Toolbar.CSS.toolbar);
/**
* Make Content Zone and Actions Zone
*/
['content', 'actions'].forEach(function (el) {
_this2.nodes[el] = $.make('div', Toolbar.CSS[el]);
$.append(_this2.nodes.wrapper, _this2.nodes[el]);
});
/**
* Fill Content Zone:
* - Plus Button
* - Toolbox
*/
this.nodes.plusButton = $.make('div', Toolbar.CSS.plusButton);
$.append(this.nodes.plusButton, $.svg('plus', 14, 14));
$.append(this.nodes.content, this.nodes.plusButton);
this.nodes.plusButton.addEventListener('click', function (event) {
return _this2.plusButtonClicked(event);
}, false);
/**
* Make a Toolbox
*/
this.Editor.Toolbox.make();
/**
* Fill Actions Zone:
* - Settings Toggler
* - Remove Block Button
* - Settings Panel
*/
this.nodes.blockActionsButtons = $.make('div', Toolbar.CSS.blockActionsButtons);
this.nodes.settingsToggler = $.make('span', Toolbar.CSS.settingsToggler);
var settingsIcon = $.svg('dots', 18, 4);
$.append(this.nodes.settingsToggler, settingsIcon);
$.append(this.nodes.blockActionsButtons, this.nodes.settingsToggler);
$.append(this.nodes.actions, this.nodes.blockActionsButtons);
/**
* Make and append Settings Panel
*/
this.Editor.BlockSettings.make();
$.append(this.nodes.actions, this.Editor.BlockSettings.nodes.wrapper);
/**
* Append toolbar to the Editor
*/
$.append(this.Editor.UI.nodes.wrapper, this.nodes.wrapper);
/**
* Bind events on the Toolbar elements
*/
this.bindEvents();
}
/**
* Move Toolbar to the Current Block
*/
}, {
key: 'move',
value: function move() {
/** Close Toolbox when we move toolbar */
this.Editor.Toolbox.close();
this.Editor.BlockSettings.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() {
this.Editor.Toolbox.toggle();
}
/**
* Bind events on the Toolbar Elements:
* - Block Settings
*/
}, {
key: 'bindEvents',
value: function bindEvents() {
var _this3 = this;
/**
* Settings toggler
*/
this.Editor.Listeners.on(this.nodes.settingsToggler, 'click', function (event) {
_this3.settingsTogglerClicked(event);
});
}
/**
* Clicks on the Block Settings toggler
*/
}, {
key: 'settingsTogglerClicked',
value: function settingsTogglerClicked() {
if (this.Editor.BlockSettings.opened) {
this.Editor.BlockSettings.close();
} else {
this.Editor.BlockSettings.open();
}
}
}, {
key: 'plusButton',
get: function get() {
var _this4 = this;
return {
hide: function hide() {
return _this4.nodes.plusButton.classList.add(Toolbar.CSS.plusButtonHidden);
},
show: function show() {
return _this4.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
blockActionsButtons: 'ce-toolbar__actions-buttons',
settingsToggler: 'ce-toolbar__settings-btn'
};
}
}]);
return Toolbar;
}(Module);
Toolbar.displayName = 'Toolbar';
exports.default = Toolbar;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! dom */ "./src/components/dom.js")))
/***/ }),
/***/ "./src/components/modules/tools.js":
/*!*****************************************!*\
!*** ./src/components/modules/tools.js ***!
\*****************************************/
/*! no static exports found */
/***/ (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 _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return 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 Codex Editor Tools Submodule
*
* Creates Instances from Plugins and binds external config to the instances
*/
/**
* Each Tool must contain the following important objects:
*
* @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
* @property {Boolean|String[]} inlineToolbar - Pass `true` to enable the Inline Toolbar with all Tools, all pass an array with specified Tools list |
* @property render @todo add description
* @property save @todo add description
* @property settings @todo add description
* @property validate - method that validates output data before saving
*/
/**
* @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);
_createClass(Tools, [{
key: 'available',
/**
* Returns available Tools
* @return {Tool[]}
*/
get: function get() {
return this.toolsAvailable;
}
/**
* Returns unavailable Tools
* @return {Tool[]}
*/
}, {
key: 'unavailable',
get: function get() {
return this.toolsUnavailable;
}
/**
* Return Tools for the Inline Toolbar
* @return {Array} - array of Inline Tool's classes
*/
}, {
key: 'inline',
get: function get() {
var _this2 = this;
return Object.values(this.available).filter(function (tool) {
if (!tool[_this2.apiSettings.IS_INLINE]) {
return false;
}
/**
* Some Tools validation
*/
var inlineToolRequiredMethods = ['render', 'surround', 'checkState'];
var notImplementedMethods = inlineToolRequiredMethods.filter(function (method) {
return !new tool()[method];
});
if (notImplementedMethods.length) {
_.log('Incorrect Inline Tool: ' + tool.name + '. Some of required methods is not implemented %o', 'warn', notImplementedMethods);
return false;
}
return true;
});
}
/**
* Constant for available Tools Settings
* @return {object}
*/
}, {
key: 'apiSettings',
get: function get() {
return {
IS_INLINE: 'isInline',
TOOLBAR_ICON_CLASS: 'iconClassName',
IS_DISPLAYED_IN_TOOLBOX: 'displayInToolbox',
IS_ENABLED_LINE_BREAKS: 'enableLineBreaks',
IS_IRREPLACEBLE_TOOL: 'irreplaceable',
IS_ENABLED_INLINE_TOOLBAR: 'inlineToolbar'
};
}
/**
* Static getter for default Tool config fields
* @return {ToolConfig}
*/
}, {
key: 'defaultConfig',
get: function get() {
var _ref;
return _ref = {}, _defineProperty(_ref, this.apiSettings.TOOLBAR_ICON_CLASS, false), _defineProperty(_ref, this.apiSettings.IS_DISPLAYED_IN_TOOLBOX, false), _defineProperty(_ref, this.apiSettings.IS_ENABLED_LINE_BREAKS, false), _defineProperty(_ref, this.apiSettings.IS_IRREPLACEBLE_TOOL, false), _defineProperty(_ref, this.apiSettings.IS_ENABLED_INLINE_TOOLBAR, false), _ref;
}
/**
* @constructor
*
* @param {EditorConfig} config
*/
}]);
function Tools(_ref2) {
var config = _ref2.config;
_classCallCheck(this, Tools);
/**
* 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;
}
/**
* Creates instances via passed or default configuration
* @return {Promise}
*/
_createClass(Tools, [{
key: 'prepare',
value: function prepare() {
var _this3 = this;
if (!this.config.hasOwnProperty('tools')) {
return Promise.reject("Can't start without tools");
}
for (var toolName in this.config.tools) {
this.toolClasses[toolName] = this.config.tools[toolName];
}
/**
* getting classes that has prepare method
*/
var sequenceData = this.getListOfPrepareFunctions();
/**
* if sequence data contains nothing then resolve current chain and run other module prepare
*/
if (sequenceData.length === 0) {
return Promise.resolve();
}
/**
* to see how it works {@link Util#sequence}
*/
return _.sequence(sequenceData, function (data) {
_this3.success(data);
}, function (data) {
_this3.fallback(data);
});
}
/**
* Binds prepare function of plugins with user or default config
* @return {Array} list of functions that needs to be fired sequentially
*/
}, {
key: 'getListOfPrepareFunctions',
value: function getListOfPrepareFunctions() {
var toolPreparationList = [];
for (var toolName in this.toolClasses) {
var toolClass = this.toolClasses[toolName];
if (typeof toolClass.prepare === 'function') {
toolPreparationList.push({
function: toolClass.prepare,
data: {
toolName: toolName
}
});
} else {
/**
* If Tool hasn't a prepare method, mark it as available
*/
this.toolsAvailable[toolName] = toolClass;
}
}
return toolPreparationList;
}
/**
* @param {ChainData.data} data - append tool to available list
*/
}, {
key: 'success',
value: function success(data) {
this.toolsAvailable[data.toolName] = this.toolClasses[data.toolName];
}
/**
* @param {ChainData.data} data - append tool to unavailable list
*/
}, {
key: 'fallback',
value: function fallback(data) {
this.toolsUnavailable[data.toolName] = this.toolClasses[data.toolName];
}
/**
* Return tool`a instance
*
* @param {String} tool — tool name
* @param {Object} data — initial data
*
* @todo throw exceptions if tool doesnt exist
*
*/
}, {
key: 'construct',
value: function construct(tool, data) {
var plugin = this.toolClasses[tool],
config = this.config.toolsConfig[tool];
var instance = new plugin(data, config || {});
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;
}(Module);
Tools.displayName = 'Tools';
exports.default = Tools;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/modules/ui.js":
/*!**************************************!*\
!*** ./src/components/modules/ui.js ***!
\**************************************/
/*! no static exports found */
/***/ (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; }; }();
var _sprite = __webpack_require__(/*! ../../../build/sprite.svg */ "./build/sprite.svg");
var _sprite2 = _interopRequireDefault(_sprite);
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}
*/
/**
* Prebuilded sprite of SVG icons
*/
/**
* @class
*
* @classdesc Makes CodeX Editor UI:
*
*
*
*
*
*
* @typedef {UI} UI
* @property {EditorConfig} config - editor configuration {@link CodexEditor#configuration}
* @property {Object} Editor - available editor modules {@link CodexEditor#moduleInstances}
* @property {Object} nodes -
* @property {Element} nodes.holder - element where we need to append redactor
* @property {Element} nodes.wrapper -
* @property {Element} nodes.redactor -
*/
var UI = function (_Module) {
_inherits(UI, _Module);
/**
* @constructor
*
* @param {EditorConfig} config
*/
function UI(_ref) {
var config = _ref.config;
_classCallCheck(this, UI);
var _this = _possibleConstructorReturn(this, (UI.__proto__ || Object.getPrototypeOf(UI)).call(this, { config: config }));
_this.nodes = {
holder: null,
wrapper: null,
redactor: null
};
return _this;
}
/**
* Making main interface
*/
_createClass(UI, [{
key: 'prepare',
value: function prepare() {
var _this2 = this;
return this.make()
/**
* Append SVG sprite
*/
.then(function () {
return _this2.appendSVGSprite();
})
/**
* Make toolbar
*/
.then(function () {
return _this2.Editor.Toolbar.make();
})
/**
* Make the Inline toolbar
*/
.then(function () {
return _this2.Editor.InlineToolbar.make();
})
/**
* Load and append CSS
*/
.then(function () {
return _this2.loadStyles();
})
/**
* Bind events for the UI elements
*/
.then(function () {
return _this2.bindEvents();
})
/** Make container for inline toolbar */
// .then(makeInlineToolbar_)
/** Add inline toolbar tools */
// .then(addInlineToolbarTools_)
/** Draw wrapper for notifications */
// .then(makeNotificationHolder_)
/** Add eventlisteners to redactor elements */
// .then(bindEvents_)
.catch(function (e) {
console.error(e);
// 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() {
/**
* Load CSS
*/
var styles = __webpack_require__(/*! ../../styles/main.css */ "./src/styles/main.css");
/**
* Make tag
*/
var tag = $.make('style', null, {
textContent: styles.toString()
});
/**
* Append styles
*/
$.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.Editor.Listeners.on(this.nodes.redactor, '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);
} catch (e) {
/**
* If clicked outside first-level Blocks, set Caret to the last empty Block
*/
this.Editor.Caret.setToTheLastBlock();
}
/**
* Close Inline Toolbar when nothing selected
*/
this.Editor.InlineToolbar.handleShowingEvent(event);
/**
*
/** 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();
}
}
/**
* Append prebuilded sprite with SVG icons
*/
}, {
key: 'appendSVGSprite',
value: function appendSVGSprite() {
var spriteHolder = $.make('div');
spriteHolder.innerHTML = _sprite2.default;
$.append(this.nodes.wrapper, spriteHolder);
}
}, {
key: 'CSS',
get: function get() {
return {
editorWrapper: 'codex-editor',
editorZone: 'codex-editor__redactor'
};
}
}]);
return UI;
}(Module);
// /**
// * Codex Editor UI module
// *
// * @author Codex Team
// * @version 1.2.0
// */
//
// module.exports = (function (ui) {
//
// let editor = codex.editor;
//
// /**
// * Basic editor classnames
// */
// ui.prepare = function () {
//
//
// };
//
// /** Draw notifications holder */
// var makeNotificationHolder_ = function () {
//
// /** Append block with notifications to the document */
// editor.nodes.notifications = editor.notifications.createHolder();
//
// };
//
//
// var addInlineToolbarTools_ = function () {
//
// var tools = {
//
// bold: {
// icon : 'ce-icon-bold',
// command : 'bold'
// },
//
// italic: {
// icon : 'ce-icon-italic',
// command : 'italic'
// },
//
// link: {
// icon : 'ce-icon-link',
// command : 'createLink'
// }
// };
//
// var toolButton,
// tool;
//
// for(var name in tools) {
//
// tool = tools[name];
//
// toolButton = editor.draw.toolbarButtonInline(name, tool.icon);
//
// editor.nodes.inlineToolbar.buttons.appendChild(toolButton);
// /**
// * Add callbacks to this buttons
// */
// editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);
//
// }
//
// };
//
// /**
// * @private
// * Bind editor UI events
// */
// var bindEvents_ = function () {
//
// editor.core.log('ui.bindEvents fired', 'info');
//
// // window.addEventListener('error', function (errorMsg, url, lineNumber) {
// // editor.notifications.errorThrown(errorMsg, event);
// // }, false );
//
// /** All keydowns on Document */
// editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);
//
// /** All keydowns on Redactor zone */
// editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);
//
// /** All keydowns on Document */
// editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );
//
// /**
// * Mouse click to radactor
// */
// editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );
//
// /**
// * Clicks to the Plus button
// */
// editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);
//
// /**
// * Clicks to SETTINGS button in toolbar
// */
// editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );
//
// /** Bind click listeners on toolbar buttons */
// for (var button in editor.nodes.toolbarButtons) {
//
// editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);
//
// }
//
// };
//
// ui.addBlockHandlers = function (block) {
//
// if (!block) return;
//
// /**
// * Block keydowns
// */
// editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);
//
// /**
// * Pasting content from another source
// * We have two type of sanitization
// * First - uses deep-first search algorithm to get sub nodes,
// * sanitizes whole Block_content and replaces cleared nodes
// * This method is deprecated
// * Method is used in editor.callback.blockPaste(event)
// *
// * Secont - uses Mutation observer.
// * Observer "observe" DOM changes and send changings to callback.
// * Callback gets changed node, not whole Block_content.
// * Inserted or changed node, which we've gotten have been cleared and replaced with diry node
// *
// * Method is used in editor.callback.blockPasteViaSanitize(event)
// *
// * @uses html-janitor
// * @example editor.callback.blockPasteViaSanitize(event), the second method.
// *
// */
// editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);
//
// /**
// * Show inline toolbar for selected text
// */
// editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);
// editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);
//
// };
//
// /** getting all contenteditable elements */
// ui.saveInputs = function () {
//
// var redactor = editor.nodes.redactor;
//
// editor.state.inputs = [];
//
// /** Save all inputs in global variable state */
// var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');
//
// Array.prototype.map.call(inputs, function (current) {
//
// if (!current.type || current.type == 'text' || current.type == 'textarea') {
//
// editor.state.inputs.push(current);
//
// }
//
// });
//
// };
//
// /**
// * Adds first initial block on empty redactor
// */
// ui.addInitialBlock = function () {
//
// var initialBlockType = editor.settings.initialBlockPlugin,
// initialBlock;
//
// if ( !editor.tools[initialBlockType] ) {
//
// editor.core.log('Plugin %o was not implemented and can\'t be used as initial block', 'warn', initialBlockType);
// return;
//
// }
//
// initialBlock = editor.tools[initialBlockType].render();
//
// initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);
//
// editor.content.insertBlock({
// type : initialBlockType,
// block : initialBlock
// });
//
// editor.content.workingNodeChanged(initialBlock);
//
// };
//
// ui.setInlineToolbarButtonBehaviour = function (button, type) {
//
// editor.listeners.add(button, 'mousedown', function (event) {
//
// editor.toolbar.inline.toolClicked(event, type);
//
// }, false);
//
// };
//
// return ui;
//
// })({});
UI.displayName = 'UI';
exports.default = UI;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../__module.ts */ "./src/components/__module.ts"), __webpack_require__(/*! dom */ "./src/components/dom.js")))
/***/ }),
/***/ "./src/components/polyfills.js":
/*!*************************************!*\
!*** ./src/components/polyfills.js ***!
\*************************************/
/*! no static exports found */
/***/ (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;
};
/***/ }),
/***/ "./src/components/selection.js":
/*!*************************************!*\
!*** ./src/components/selection.js ***!
\*************************************/
/*! no static exports found */
/***/ (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"); } }
/**
* Working with selection
* @typedef {Selection} Selection
*/
var Selection = function () {
/**
* @constructor
*/
function Selection() {
_classCallCheck(this, Selection);
this.instance = null;
this.selection = null;
/**
* This property can store Selection's range for restoring later
* @type {Range|null}
*/
this.savedSelectionRange = null;
}
/**
* Returns window Selection
* {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}
* @return {Selection}
*/
_createClass(Selection, [{
key: 'save',
/**
* Save Selection's range
*/
value: function save() {
this.savedSelectionRange = Selection.range;
}
/**
* Restore saved Selection's range
*/
}, {
key: 'restore',
value: function restore() {
if (!this.savedSelectionRange) {
return;
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(this.savedSelectionRange);
}
/**
* Clears saved selection
*/
}, {
key: 'clearSaved',
value: function clearSaved() {
this.savedSelectionRange = null;
}
/**
* Looks ahead to find passed tag from current selection
*
* Read more about selection's Nodes on https://stackoverflow.com/a/33586253
*
* @param {String} tagName - tag to found
* @param {String} [className] - tag's class name
* @param {Number} [searchDepth] - count of tags that can be included. For better performance.
* @return {Node|null}
*/
}, {
key: 'findParentTag',
value: function findParentTag(tagName, className) {
var searchDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var selection = window.getSelection(),
parentTag = null;
/**
* If selection is missing or no anchorNode or focusNode were found then return null
*/
if (!selection || !selection.anchorNode || !selection.focusNode) {
return null;
}
/**
* Define Nodes for start and end of selection
*/
var parents = [
/** the Node in which the selection begins */
selection.anchorNode.parentNode,
/** the Node in which the selection ends */
selection.focusNode.parentNode];
/**
* For each selection parent Nodes we try to find target tag [with target class name]
* It would be saved in parentTag variable
*/
parents.forEach(function (parent) {
/** Reset tags limit */
var searchDepthIterable = searchDepth;
while (searchDepthIterable > 0 && parent.parentNode) {
/**
* Check tag's name
*/
if (parent.tagName === tagName) {
/**
* Optional additional check for class-name matching
*/
if (className && !parent.classList.contains(className)) {
break;
}
/**
* If we have found required tag with class then save the result and go out from cycle
*/
parentTag = parent;
break;
}
/**
* Target tag was not found. Go up to the parent and check it
*/
parent = parent.parentNode;
searchDepthIterable--;
}
});
/**
* Return found tag or null
*/
return parentTag;
}
/**
* Expands selection range to the passed parent node
*
* @param {HTMLElement} node
*/
}, {
key: 'expandToTag',
value: function expandToTag(node) {
var selection = window.getSelection();
selection.removeAllRanges();
var range = document.createRange();
range.selectNodeContents(node);
selection.addRange(range);
}
}], [{
key: 'get',
value: function get() {
return window.getSelection();
}
/**
* Returns selected anchor
* {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorNode}
* @return {Node|null}
*/
}, {
key: 'anchorNode',
get: function get() {
var selection = window.getSelection();
return selection ? selection.anchorNode : null;
}
/**
* Returns selection offset according to the anchor node
* {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorOffset}
* @return {Number|null}
*/
}, {
key: 'anchorOffset',
get: function get() {
var selection = window.getSelection();
return selection ? selection.anchorOffset : null;
}
/**
* Is current selection range collapsed
* @return {boolean|null}
*/
}, {
key: 'isCollapsed',
get: function get() {
var selection = window.getSelection();
return selection ? selection.isCollapsed : null;
}
/**
* Return first range
* @return {Range|null}
*/
}, {
key: 'range',
get: function get() {
var selection = window.getSelection();
return selection && selection.rangeCount ? selection.getRangeAt(0) : null;
}
/**
* Calculates position and size of selected text
* @return {{x, y, width, height, top?, left?, bottom?, right?}}
*/
}, {
key: 'rect',
get: function get() {
var sel = document.selection,
range = void 0;
var rect = {
x: 0,
y: 0,
width: 0,
height: 0
};
if (sel && sel.type !== 'Control') {
range = sel.createRange();
rect.x = range.boundingLeft;
rect.y = range.boundingTop;
rect.width = range.boundingWidth;
rect.height = range.boundingHeight;
return rect;
}
if (!window.getSelection) {
_.log('Method window.getSelection is not supported', 'warn');
return rect;
}
sel = window.getSelection();
if (!sel.rangeCount) {
_.log('Method Selection.rangeCount() is not supported', 'warn');
return rect;
}
range = sel.getRangeAt(0).cloneRange();
if (range.getBoundingClientRect) {
rect = range.getBoundingClientRect();
}
// Fall back to inserting a temporary element
if (rect.x === 0 && rect.y === 0) {
var span = document.createElement('span');
if (span.getBoundingClientRect) {
// Ensure span has dimensions and position by
// adding a zero-width space character
span.appendChild(document.createTextNode('\u200B'));
range.insertNode(span);
rect = span.getBoundingClientRect();
var spanParent = span.parentNode;
spanParent.removeChild(span);
// Glue any broken text nodes back together
spanParent.normalize();
}
}
return rect;
}
/**
* Returns selected text as String
* @returns {string}
*/
}, {
key: 'text',
get: function get() {
return window.getSelection ? window.getSelection().toString() : '';
}
}]);
return Selection;
}();
Selection.displayName = 'Selection';
exports.default = Selection;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! utils */ "./src/components/utils.js")))
/***/ }),
/***/ "./src/components/utils.js":
/*!*********************************!*\
!*** ./src/components/utils.js ***!
\*********************************/
/*! no static exports found */
/***/ (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
}
}
/**
* Returns basic keycodes as constants
* @return {{}}
*/
}, {
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;
}
/**
* Check if passed object is a Promise
* @param {*} object - object to check
* @return {Boolean}
*/
}, {
key: 'isPromise',
value: function isPromise(object) {
return Promise.resolve(object) === object;
}
/**
* Check if passed element is contenteditable
* @param element
* @return {boolean}
*/
}, {
key: 'isContentEditable',
value: function isContentEditable(element) {
return element.contentEditable === 'true';
}
/**
* Delays method execution
*
* @param method
* @param timeout
*/
}, {
key: 'delay',
value: function delay(method, timeout) {
return function () {
var context = this,
args = arguments;
window.setTimeout(function () {
return method.apply(context, args);
}, timeout);
};
}
}, {
key: 'keyCodes',
get: function get() {
return {
BACKSPACE: 8,
TAB: 9,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
ESC: 27,
SPACE: 32,
LEFT: 37,
UP: 38,
DOWN: 40,
RIGHT: 39,
DELETE: 46,
META: 91
};
}
}]);
return Util;
}();
Util.displayName = 'Util';
exports.default = Util;
;
module.exports = exports['default'];
/***/ }),
/***/ "./src/styles/main.css":
/*!*****************************!*\
!*** ./src/styles/main.css ***!
\*****************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(/*! ../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false);
// imports
// module
exports.push([module.i, ":root {\n /**\n * Toolbar buttons\n */\n --bg-light: #eff2f5;\n\n /**\n * All gray texts: placeholders, settings\n */\n --grayText: #707684;\n\n /** Blue icons */\n --color-active-icon: #388AE5;\n\n /**\n * Block content width\n */\n --content-width: 650px;\n\n /**\n * Toolbar Plus Button and Toolbox buttons height and width\n */\n --toolbar-buttons-size: 34px;\n\n /**\n * Confirm deletion bg\n */\n --color-confirm: #E24A4A;\n}\n/**\n* Editor wrapper\n*/\n.codex-editor {\n position: relative;\n box-sizing: border-box;\n\n\n}\n.codex-editor .hide {\n display: none;\n }\n.codex-editor__redactor {\n padding-bottom: 300px;\n }\n.codex-editor svg {\n fill: currentColor;\n vertical-align: middle;\n max-height: 100%;\n }\n::-moz-selection{\n background-color: rgba(61,166,239,0.63);\n}\n::selection{\n background-color: rgba(61,166,239,0.63);\n}\n.ce-tune-moveup{}\n.ce-settings-delete:hover {\n cursor: pointer;\n }\n.ce-settings-delete::before {\n content: 'delete'\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 display: none;\n}\n.ce-toolbar--opened {\n display: block;\n /*opacity: 1;*/\n /*visibility: visible;*/\n }\n.ce-toolbar__content {\n max-width: 650px;\n max-width: var(--content-width);\n margin: 0 auto;\n position: relative;\n }\n.ce-toolbar__plus {\n position: absolute;\n left: calc(calc(34px + 10px) * -1);\n left: calc(calc(var(--toolbar-buttons-size) + 10px) * -1);\n display: inline-block;\n background-color: #eff2f5;\n background-color: var(--bg-light);\n width: 34px;\n width: var(--toolbar-buttons-size);\n height: 34px;\n height: var(--toolbar-buttons-size);\n line-height: 34px;\n text-align: center;\n border-radius: 50%;\n cursor: pointer;\n }\n.ce-toolbar__plus--hidden {\n display: none;\n }\n/**\n * Block actions Zone\n * -------------------------\n */\n.ce-toolbar__actions {\n position: absolute;\n right: 0;\n top: 0;\n padding-right: 16px;\n }\n.ce-toolbar__actions-buttons {\n text-align: right;\n }\n.ce-toolbar__settings-btn {\n display: inline-block;\n width: 24px;\n height: 24px;\n color: #707684;\n color: var(--grayText);\n cursor: pointer;\n }\n.ce-toolbox {\n position: absolute;\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 background: var(--bg-light);\n width: 34px;\n width: var(--toolbar-buttons-size);\n height: 34px;\n height: var(--toolbar-buttons-size);\n border-radius: 30px;\n overflow: hidden;\n text-align: center;\n line-height: 34px;\n line-height: var(--toolbar-buttons-size)\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.ce-inline-toolbar {\n position: absolute;\n background: #FFFFFF;\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\n border-radius: 4px;\n z-index: 2\n}\n.ce-inline-toolbar::before {\n content: '';\n width: 15px;\n height: 15px;\n position: absolute;\n top: -7px;\n left: 50%;\n margin-left: -7px;\n transform: rotate(-45deg);\n background: #fff;\n z-index: -1;\n }\n.ce-inline-toolbar {\n padding: 6px;\n transform: translateX(-50%);\n display: none;\n box-shadow: 0 6px 12px -6px rgba(131, 147, 173, 0.46),\n 5px -12px 34px -13px rgba(97, 105, 134, 0.6),\n 0 26px 52px 3px rgba(147, 165, 186, 0.24);\n}\n.ce-inline-toolbar--showed {\n display: block;\n }\n.ce-inline-tool {\n display: inline-block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n border-radius: 3px;\n cursor: pointer;\n border: 0;\n outline: none;\n background: transparent;\n vertical-align: bottom;\n color: #707684;\n color: var(--grayText)\n}\n.ce-inline-tool:not(:last-of-type){\n margin-right: 5px;\n }\n.ce-inline-tool:hover {\n background: #eff2f5;\n background: var(--bg-light);\n }\n.ce-inline-tool {\n line-height: normal;\n}\n.ce-inline-tool--active {\n color: #388AE5;\n color: var(--color-active-icon);\n }\n.ce-inline-tool--link .icon {\n margin-top: -2px;\n }\n.ce-inline-tool--link .icon--unlink {\n display: none;\n }\n.ce-inline-tool--unlink .icon--link {\n display: none;\n }\n.ce-inline-tool--unlink .icon--unlink {\n display: inline-block;\n }\n.ce-inline-tool-input {\n background: #eff2f5;\n background: var(--bg-light);\n outline: none;\n border: 0;\n border-radius: 3px;\n margin: 6px 0 0;\n font-size: 13px;\n padding: 8px;\n width: 100%;\n box-sizing: border-box;\n display: none\n }\n.ce-inline-tool-input::-webkit-input-placeholder {\n color: #707684;\n color: var(--grayText);\n }\n.ce-inline-tool-input:-ms-input-placeholder {\n color: #707684;\n color: var(--grayText);\n }\n.ce-inline-tool-input::placeholder {\n color: #707684;\n color: var(--grayText);\n }\n.ce-inline-tool-input--showed {\n display: block;\n }\n.ce-settings {\n position: absolute;\n background: #FFFFFF;\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\n border-radius: 4px;\n z-index: 2\n}\n.ce-settings::before {\n content: '';\n width: 15px;\n height: 15px;\n position: absolute;\n top: -7px;\n left: 50%;\n margin-left: -7px;\n transform: rotate(-45deg);\n background: #fff;\n z-index: -1;\n }\n.ce-settings {\n right: 5px;\n top: 35px;\n min-width: 124px\n}\n.ce-settings::before{\n left: auto;\n right: 12px;\n }\n.ce-settings {\n\n display: none;\n}\n.ce-settings--opened {\n display: block;\n }\n.ce-settings__plugin-zone:not(:empty){\n padding: 6px;\n }\n.ce-settings__default-zone:not(:empty){\n padding: 6px;\n }\n.ce-settings__button {\n display: inline-block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n border-radius: 3px;\n cursor: pointer;\n border: 0;\n outline: none;\n background: transparent;\n vertical-align: bottom;\n color: #707684;\n color: var(--grayText)\n }\n.ce-settings__button:not(:last-of-type){\n margin-right: 5px;\n }\n.ce-settings__button:hover {\n background: #eff2f5;\n background: var(--bg-light);\n }\n.ce-settings__button--active {\n color: #388AE5;\n color: var(--color-active-icon);\n }\n.ce-settings__button--delete {\n transition: background-color 300ms ease;\n will-change: background-color;\n }\n.ce-settings__button--delete .icon {\n transition: transform 200ms ease-out;\n will-change: transform;\n }\n.ce-settings__button--confirm {\n background-color: #E24A4A;\n background-color: var(--color-confirm);\n color: #fff\n }\n.ce-settings__button--confirm:hover {\n background-color: rgb(213, 74, 74) !important;\n background-color: rgb(213, 74, 74) !important;\n }\n.ce-settings__button--confirm .icon {\n transform: rotate(90deg);\n }\n.ce-settings-move-up:hover {\n cursor: pointer;\n }\n.ce-settings-move-up::before {\n display: inline-block;\n content: 'up';\n }\n.ce-block:first-of-type {\n margin-top: 0;\n }\n.ce-block--selected {\n background-image: linear-gradient(17deg, rgba(243, 248, 255, 0.03) 63.45%, rgba(207, 214, 229, 0.27) 98%);\n border-radius: 3px;\n }\n.ce-block__content {\n max-width: 650px;\n max-width: var(--content-width);\n margin: 0 auto;\n }\n", ""]);
// exports
/***/ })
/******/ });
//# sourceMappingURL=codex-editor.js.map