*
* @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;
}
/**
* Set's caret to the next Block
* Before moving caret, we should check if caret position is at the end of Plugins node
* Using {@link Dom#getDeepestNode} to get a last node and match with current selection
*
* @param {Boolean} force - force navigation even if caret is not at the end
*
* @return {Boolean}
*/
}, {
key: 'navigateNext',
value: function navigateNext() {
var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var nextBlock = this.Editor.BlockManager.nextBlock;
if (!nextBlock) {
return false;
}
if (force || this.isAtEnd) {
this.setToBlock(nextBlock);
return true;
}
return false;
}
/**
* Set's caret to the previous Block
* Before moving caret, we should check if caret position is start of the Plugins node
* Using {@link Dom#getDeepestNode} to get a last node and match with current selection
*
* @param {Boolean} force - force navigation even if caret is not at the start
*
* @return {Boolean}
*/
}, {
key: 'navigatePrevious',
value: function navigatePrevious() {
var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var previousBlock = this.Editor.BlockManager.previousBlock;
if (!previousBlock) {
return false;
}
if (force || this.isAtStart) {
this.setToBlock(previousBlock, 0, true);
return true;
}
return false;
}
/**
* Get's deepest first node and checks if offset is zero
* @return {boolean}
*/
}, {
key: 'createShadow',
/**
* Inserts shadow element after passed element where caret can be placed
* @param {Node} element
*/
value: function createShadow(element) {
var shadowCaret = document.createElement('span');
shadowCaret.classList.add(Caret.CSS.shadowCaret);
element.insertAdjacentElement('beforeEnd', shadowCaret);
}
/**
* Restores caret position
* @param {Node} element
*/
}, {
key: 'restoreCaret',
value: function restoreCaret(element) {
var shadowCaret = element.querySelector('.' + Caret.CSS.shadowCaret);
if (!shadowCaret) {
return;
}
/**
* After we set the caret to the required place
* we need to clear shadow caret
*
* - make new range
* - select shadowed span
* - use extractContent to remove it from DOM
*/
var sel = new _selection2.default();
sel.expandToTag(shadowCaret);
setTimeout(function () {
var newRange = document.createRange();
newRange.selectNode(shadowCaret);
newRange.extractContents();
}, 50);
}
}, {
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;
}
}
/**
* We use <= comparison for case:
* "| Hello" <--- selection.anchorOffset is 0, but firstLetterPosition is 1
*/
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;
}
}
/**
* Workaround case:
* hello | <--- anchorOffset will be 5, but textContent.length will be 6.
* Why not regular .trim():
* in case of ' hello |' trim() will also remove space at the beginning, so length will be lower than anchorOffset
*/
var rightTrimmedText = lastNode.textContent.replace(/\s+$/, '');
/**
* We use >= comparison for case:
* "Hello |" <--- selection.anchorOffset is 7, but rightTrimmedText is 6
*/
return anchorNode === lastNode && selection.anchorOffset >= rightTrimmedText.length;
}
}], [{
key: 'CSS',
get: function get() {
return {
shadowCaret: 'cdx-shadow-caret'
};
}
}]);
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/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;
if (tool in this.Editor.Tools.available) {
this.Editor.BlockManager.insert(tool, data, settings);
} else {
/**
* @todo show warning notification message
*
* `${tool} blocks was skipped.`
*/
_.log('Tool \xAB' + tool + '\xBB is not found. Check \'tools\' property at your initial CodeX Editor config.', 'warn');
}
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({
type: extraction.tool,
data: 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.renderSettings === 'function') {
$.append(this.nodes.toolSettings, this.Editor.BlockManager.currentBlock.tool.renderSettings());
}
}
/**
* 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);
/**
* CSS styles
*/
var _this = _possibleConstructorReturn(this, (InlineToolbar.__proto__ || Object.getPrototypeOf(InlineToolbar)).call(this, { config: config }));
_this.CSS = {
inlineToolbar: 'ce-inline-toolbar',
inlineToolbarShowed: 'ce-inline-toolbar--showed',
buttonsWrapper: 'ce-inline-toolbar__buttons',
actionsWrapper: 'ce-inline-toolbar__actions'
};
/**
* Inline Toolbar elements
*/
_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
};
/**
* 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
* @param {Boolean} forceClose - force close Toolbar Settings and Toolbar
*/
}, {
key: 'move',
value: function move() {
var forceClose = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
if (forceClose) {
/** 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)';
}
/**
* 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/toolbar/inline.js":
/*!**************************************************!*\
!*** ./src/components/modules/toolbar/inline.js ***!
\**************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Inline toolbar
*
* Contains from tools:
* Bold, Italic, Underline and Anchor
*
* @author Codex Team
* @version 1.0
*/
module.exports = function (inline) {
var editor = codex.editor;
inline.buttonsOpened = null;
inline.actionsOpened = null;
inline.wrappersOffset = null;
/**
* saving selection that need for execCommand for styling
*
*/
inline.storedSelection = null;
/**
* @protected
*
* Open inline toobar
*/
inline.show = function () {
var currentNode = editor.content.currentNode,
tool = currentNode.dataset.tool,
plugin;
/**
* tool allowed to open inline toolbar
*/
plugin = editor.tools[tool];
if (!plugin.showInlineToolbar) return;
var selectedText = inline.getSelectionText(),
toolbar = editor.nodes.inlineToolbar.wrapper;
if (selectedText.length > 0) {
/** Move toolbar and open */
editor.toolbar.inline.move();
/** Open inline toolbar */
toolbar.classList.add('opened');
/** show buttons of inline toolbar */
editor.toolbar.inline.showButtons();
}
};
/**
* @protected
*
* Closes inline toolbar
*/
inline.close = function () {
var toolbar = editor.nodes.inlineToolbar.wrapper;
toolbar.classList.remove('opened');
};
/**
* @private
*
* Moving toolbar
*/
inline.move = function () {
if (!this.wrappersOffset) {
this.wrappersOffset = this.getWrappersOffset();
}
var coords = this.getSelectionCoords(),
defaultOffset = 0,
toolbar = editor.nodes.inlineToolbar.wrapper,
newCoordinateX,
newCoordinateY;
if (toolbar.offsetHeight === 0) {
defaultOffset = 40;
}
newCoordinateX = coords.x - this.wrappersOffset.left;
newCoordinateY = coords.y + window.scrollY - this.wrappersOffset.top - defaultOffset - toolbar.offsetHeight;
toolbar.style.transform = 'translate3D(' + Math.floor(newCoordinateX) + 'px, ' + Math.floor(newCoordinateY) + 'px, 0)';
/** Close everything */
editor.toolbar.inline.closeButtons();
editor.toolbar.inline.closeAction();
};
/**
* @private
*
* Tool Clicked
*/
inline.toolClicked = function (event, type) {
/**
* For simple tools we use default browser function
* For more complicated tools, we should write our own behavior
*/
switch (type) {
case 'createLink':
editor.toolbar.inline.createLinkAction(event, type);break;
default:
editor.toolbar.inline.defaultToolAction(type);break;
}
/**
* highlight buttons
* after making some action
*/
editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);
};
/**
* @private
*
* Saving wrappers offset in DOM
*/
inline.getWrappersOffset = function () {
var wrapper = editor.nodes.wrapper,
offset = this.getOffset(wrapper);
this.wrappersOffset = offset;
return offset;
};
/**
* @private
*
* Calculates offset of DOM element
*
* @param el
* @returns {{top: number, left: number}}
*/
inline.getOffset = function (el) {
var _x = 0;
var _y = 0;
while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
_x += el.offsetLeft + el.clientLeft;
_y += el.offsetTop + el.clientTop;
el = el.offsetParent;
}
return { top: _y, left: _x };
};
/**
* @private
*
* Calculates position of selected text
* @returns {{x: number, y: number}}
*/
inline.getSelectionCoords = function () {
var sel = document.selection,
range;
var x = 0,
y = 0;
if (sel) {
if (sel.type != 'Control') {
range = sel.createRange();
range.collapse(true);
x = range.boundingLeft;
y = range.boundingTop;
}
} else if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0).cloneRange();
if (range.getClientRects) {
range.collapse(true);
var rect = range.getClientRects()[0];
if (!rect) {
return;
}
x = rect.left;
y = rect.top;
}
}
}
return { x: x, y: y };
};
/**
* @private
*
* Returns selected text as String
* @returns {string}
*/
inline.getSelectionText = function () {
var selectedText = '';
// all modern browsers and IE9+
if (window.getSelection) {
selectedText = window.getSelection().toString();
}
return selectedText;
};
/** Opens buttons block */
inline.showButtons = function () {
var buttons = editor.nodes.inlineToolbar.buttons;
buttons.classList.add('opened');
editor.toolbar.inline.buttonsOpened = true;
/** highlight buttons */
editor.nodes.inlineToolbar.buttons.childNodes.forEach(editor.toolbar.inline.hightlight);
};
/** Makes buttons disappear */
inline.closeButtons = function () {
var buttons = editor.nodes.inlineToolbar.buttons;
buttons.classList.remove('opened');
editor.toolbar.inline.buttonsOpened = false;
};
/** Open buttons defined action if exist */
inline.showActions = function () {
var action = editor.nodes.inlineToolbar.actions;
action.classList.add('opened');
editor.toolbar.inline.actionsOpened = true;
};
/** Close actions block */
inline.closeAction = function () {
var action = editor.nodes.inlineToolbar.actions;
action.innerHTML = '';
action.classList.remove('opened');
editor.toolbar.inline.actionsOpened = false;
};
/**
* Callback for keydowns in inline toolbar "Insert link..." input
*/
var inlineToolbarAnchorInputKeydown_ = function inlineToolbarAnchorInputKeydown_(event) {
if (event.keyCode != editor.core.keys.ENTER) {
return;
}
var editable = editor.content.currentNode,
storedSelection = editor.toolbar.inline.storedSelection;
editor.toolbar.inline.restoreSelection(editable, storedSelection);
editor.toolbar.inline.setAnchor(this.value);
/**
* Preventing events that will be able to happen
*/
event.preventDefault();
event.stopImmediatePropagation();
editor.toolbar.inline.clearRange();
};
/** Action for link creation or for setting anchor */
inline.createLinkAction = function (event) {
var isActive = this.isLinkActive();
var editable = editor.content.currentNode,
storedSelection = editor.toolbar.inline.saveSelection(editable);
/** Save globally selection */
editor.toolbar.inline.storedSelection = storedSelection;
if (isActive) {
/**
* Changing stored selection. if we want to remove anchor from word
* we should remove anchor from whole word, not only selected part.
* The solution is than we get the length of current link
* Change start position to - end of selection minus length of anchor
*/
editor.toolbar.inline.restoreSelection(editable, storedSelection);
editor.toolbar.inline.defaultToolAction('unlink');
} else {
/** Create input and close buttons */
var action = editor.draw.inputForLink();
editor.nodes.inlineToolbar.actions.appendChild(action);
editor.toolbar.inline.closeButtons();
editor.toolbar.inline.showActions();
/**
* focus to input
* Solution: https://developer.mozilla.org/ru/docs/Web/API/HTMLElement/focus
* Prevents event after showing input and when we need to focus an input which is in unexisted form
*/
action.focus();
event.preventDefault();
/** Callback to link action */
editor.listeners.add(action, 'keydown', inlineToolbarAnchorInputKeydown_, false);
}
};
inline.isLinkActive = function () {
var isActive = false;
editor.nodes.inlineToolbar.buttons.childNodes.forEach(function (tool) {
var dataType = tool.dataset.type;
if (dataType == 'link' && tool.classList.contains('hightlighted')) {
isActive = true;
}
});
return isActive;
};
/** default action behavior of tool */
inline.defaultToolAction = function (type) {
document.execCommand(type, false, null);
};
/**
* @private
*
* Sets URL
*
* @param {String} url - URL
*/
inline.setAnchor = function (url) {
document.execCommand('createLink', false, url);
/** Close after URL inserting */
editor.toolbar.inline.closeAction();
};
/**
* @private
*
* Saves selection
*/
inline.saveSelection = function (containerEl) {
var range = window.getSelection().getRangeAt(0),
preSelectionRange = range.cloneRange(),
start;
preSelectionRange.selectNodeContents(containerEl);
preSelectionRange.setEnd(range.startContainer, range.startOffset);
start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
};
};
/**
* @private
*
* Sets to previous selection (Range)
*
* @param {Element} containerEl - editable element where we restore range
* @param {Object} savedSel - range basic information to restore
*/
inline.restoreSelection = function (containerEl, savedSel) {
var range = document.createRange(),
charIndex = 0;
range.setStart(containerEl, 0);
range.collapse(true);
var nodeStack = [containerEl],
node,
foundStart = false,
stop = false,
nextCharIndex;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
};
/**
* @private
*
* Removes all ranges from window selection
*/
inline.clearRange = function () {
var selection = window.getSelection();
selection.removeAllRanges();
};
/**
* @private
*
* sets or removes hightlight
*/
inline.hightlight = function (tool) {
var dataType = tool.dataset.type;
if (document.queryCommandState(dataType)) {
editor.toolbar.inline.setButtonHighlighted(tool);
} else {
editor.toolbar.inline.removeButtonsHighLight(tool);
}
/**
*
* hightlight for anchors
*/
var selection = window.getSelection(),
tag = selection.anchorNode.parentNode;
if (tag.tagName == 'A' && dataType == 'link') {
editor.toolbar.inline.setButtonHighlighted(tool);
}
};
/**
* @private
*
* Mark button if text is already executed
*/
inline.setButtonHighlighted = function (button) {
button.classList.add('hightlighted');
/** At link tool we also change icon */
if (button.dataset.type == 'link') {
var icon = button.childNodes[0];
icon.classList.remove('ce-icon-link');
icon.classList.add('ce-icon-unlink');
}
};
/**
* @private
*
* Removes hightlight
*/
inline.removeButtonsHighLight = function (button) {
button.classList.remove('hightlighted');
/** At link tool we also change icon */
if (button.dataset.type == 'link') {
var icon = button.childNodes[0];
icon.classList.remove('ce-icon-unlink');
icon.classList.add('ce-icon-link');
}
};
return inline;
}({});
/***/ }),
/***/ "./src/components/modules/toolbar/settings.js":
/*!****************************************************!*\
!*** ./src/components/modules/toolbar/settings.js ***!
\****************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Toolbar settings
*
* @version 1.0.5
*/
module.exports = function (settings) {
var editor = codex.editor;
settings.opened = false;
settings.setting = null;
settings.actions = null;
/**
* Append and open settings
*/
settings.open = function (toolType) {
/**
* Append settings content
* It's stored in tool.settings
*/
if (!editor.tools[toolType] || !editor.tools[toolType].renderSettings) {
return;
}
/**
* Draw settings block
*/
var settingsBlock = editor.tools[toolType].renderSettings();
editor.nodes.pluginSettings.appendChild(settingsBlock);
/** Open settings block */
editor.nodes.blockSettings.classList.add('opened');
this.opened = true;
};
/**
* Close and clear settings
*/
settings.close = function () {
editor.nodes.blockSettings.classList.remove('opened');
editor.nodes.pluginSettings.innerHTML = '';
this.opened = false;
};
/**
* @param {string} toolType - plugin type
*/
settings.toggle = function (toolType) {
if (!this.opened) {
this.open(toolType);
} else {
this.close();
}
};
/**
* Here we will draw buttons and add listeners to components
*/
settings.makeRemoveBlockButton = function () {
var removeBlockWrapper = editor.draw.node('SPAN', 'ce-toolbar__remove-btn', {}),
settingButton = editor.draw.node('SPAN', 'ce-toolbar__remove-setting', { innerHTML: '' }),
actionWrapper = editor.draw.node('DIV', 'ce-toolbar__remove-confirmation', {}),
confirmAction = editor.draw.node('DIV', 'ce-toolbar__remove-confirm', { textContent: 'Удалить блок' }),
cancelAction = editor.draw.node('DIV', 'ce-toolbar__remove-cancel', { textContent: 'Отмена' });
editor.listeners.add(settingButton, 'click', editor.toolbar.settings.removeButtonClicked, false);
editor.listeners.add(confirmAction, 'click', editor.toolbar.settings.confirmRemovingRequest, false);
editor.listeners.add(cancelAction, 'click', editor.toolbar.settings.cancelRemovingRequest, false);
actionWrapper.appendChild(confirmAction);
actionWrapper.appendChild(cancelAction);
removeBlockWrapper.appendChild(settingButton);
removeBlockWrapper.appendChild(actionWrapper);
/** Save setting */
editor.toolbar.settings.setting = settingButton;
editor.toolbar.settings.actions = actionWrapper;
return removeBlockWrapper;
};
settings.removeButtonClicked = function () {
var action = editor.toolbar.settings.actions;
if (action.classList.contains('opened')) {
editor.toolbar.settings.hideRemoveActions();
} else {
editor.toolbar.settings.showRemoveActions();
}
editor.toolbar.toolbox.close();
editor.toolbar.settings.close();
};
settings.cancelRemovingRequest = function () {
editor.toolbar.settings.actions.classList.remove('opened');
};
settings.confirmRemovingRequest = function () {
var currentBlock = editor.content.currentNode,
firstLevelBlocksCount;
currentBlock.remove();
firstLevelBlocksCount = editor.nodes.redactor.childNodes.length;
/**
* If all blocks are removed
*/
if (firstLevelBlocksCount === 0) {
/** update currentNode variable */
editor.content.currentNode = null;
/** Inserting new empty initial block */
editor.ui.addInitialBlock();
}
editor.ui.saveInputs();
editor.toolbar.close();
};
settings.showRemoveActions = function () {
editor.toolbar.settings.actions.classList.add('opened');
};
settings.hideRemoveActions = function () {
editor.toolbar.settings.actions.classList.remove('opened');
};
return settings;
}({});
/***/ }),
/***/ "./src/components/modules/toolbar/toolbar.js":
/*!***************************************************!*\
!*** ./src/components/modules/toolbar/toolbar.js ***!
\***************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Codex Editor toolbar module
*
* Contains:
* - Inline toolbox
* - Toolbox within plus button
* - Settings section
*
* @author Codex Team
* @version 1.0
*/
module.exports = function (toolbar) {
var editor = codex.editor;
toolbar.settings = __webpack_require__(/*! ./settings */ "./src/components/modules/toolbar/settings.js");
toolbar.inline = __webpack_require__(/*! ./inline */ "./src/components/modules/toolbar/inline.js");
toolbar.toolbox = __webpack_require__(/*! ./toolbox */ "./src/components/modules/toolbar/toolbox.js");
/**
* Margin between focused node and toolbar
*/
toolbar.defaultToolbarHeight = 49;
toolbar.defaultOffset = 34;
toolbar.opened = false;
toolbar.current = null;
/**
* @protected
*/
toolbar.open = function () {
if (editor.hideToolbar) {
return;
}
var toolType = editor.content.currentNode.dataset.tool;
if (!editor.tools[toolType] || !editor.tools[toolType].renderSettings) {
editor.nodes.showSettingsButton.classList.add('hide');
} else {
editor.nodes.showSettingsButton.classList.remove('hide');
}
editor.nodes.toolbar.classList.add('opened');
this.opened = true;
};
/**
* @protected
*/
toolbar.close = function () {
editor.nodes.toolbar.classList.remove('opened');
toolbar.opened = false;
toolbar.current = null;
for (var button in editor.nodes.toolbarButtons) {
editor.nodes.toolbarButtons[button].classList.remove('selected');
}
/** Close toolbox when toolbar is not displayed */
editor.toolbar.toolbox.close();
editor.toolbar.settings.close();
};
toolbar.toggle = function () {
if (!this.opened) {
this.open();
} else {
this.close();
}
};
toolbar.hidePlusButton = function () {
editor.nodes.plusButton.classList.add('hide');
};
toolbar.showPlusButton = function () {
editor.nodes.plusButton.classList.remove('hide');
};
/**
* Moving toolbar to the specified node
*/
toolbar.move = function () {
/** Close Toolbox when we move toolbar */
editor.toolbar.toolbox.close();
if (!editor.content.currentNode) {
return;
}
var newYCoordinate = editor.content.currentNode.offsetTop - editor.toolbar.defaultToolbarHeight / 2 + editor.toolbar.defaultOffset;
editor.nodes.toolbar.style.transform = 'translate3D(0, ' + Math.floor(newYCoordinate) + 'px, 0)';
/** Close trash actions */
editor.toolbar.settings.hideRemoveActions();
};
return toolbar;
}({});
/***/ }),
/***/ "./src/components/modules/toolbar/toolbox.js":
/*!***************************************************!*\
!*** ./src/components/modules/toolbar/toolbox.js ***!
\***************************************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Codex Editor toolbox
*
* All tools be able to appended here
*
* @author Codex Team
* @version 1.0
*/
module.exports = function (toolbox) {
var editor = codex.editor;
toolbox.opened = false;
toolbox.openedOnBlock = null;
/** Shows toolbox */
toolbox.open = function () {
/** Close setting if toolbox is opened */
if (editor.toolbar.settings.opened) {
editor.toolbar.settings.close();
}
/** Add 'toolbar-opened' class for current block **/
toolbox.openedOnBlock = editor.content.currentNode;
toolbox.openedOnBlock.classList.add('toolbar-opened');
/** display toolbox */
editor.nodes.toolbox.classList.add('opened');
/** Animate plus button */
editor.nodes.plusButton.classList.add('clicked');
/** toolbox state */
editor.toolbar.toolbox.opened = true;
};
/** Closes toolbox */
toolbox.close = function () {
/** Remove 'toolbar-opened' class from current block **/
if (toolbox.openedOnBlock) toolbox.openedOnBlock.classList.remove('toolbar-opened');
toolbox.openedOnBlock = null;
/** Makes toolbox disappear */
editor.nodes.toolbox.classList.remove('opened');
/** Rotate plus button */
editor.nodes.plusButton.classList.remove('clicked');
/** toolbox state */
editor.toolbar.toolbox.opened = false;
editor.toolbar.current = null;
};
toolbox.leaf = function () {
var currentTool = editor.toolbar.current,
tools = Object.keys(editor.tools),
barButtons = editor.nodes.toolbarButtons,
nextToolIndex = 0,
toolToSelect = void 0,
visibleTool = void 0,
tool = void 0;
if (!currentTool) {
/** Get first tool from object*/
for (tool in editor.tools) {
if (editor.tools[tool].displayInToolbox) {
break;
}
nextToolIndex++;
}
} else {
nextToolIndex = (tools.indexOf(currentTool) + 1) % tools.length;
visibleTool = tools[nextToolIndex];
while (!editor.tools[visibleTool].displayInToolbox) {
nextToolIndex = (nextToolIndex + 1) % tools.length;
visibleTool = tools[nextToolIndex];
}
}
toolToSelect = tools[nextToolIndex];
for (var button in barButtons) {
barButtons[button].classList.remove('selected');
}
barButtons[toolToSelect].classList.add('selected');
editor.toolbar.current = toolToSelect;
};
/**
* Transforming selected node type into selected toolbar element type
* @param {event} event
*/
toolbox.toolClicked = function (event) {
/**
* UNREPLACEBLE_TOOLS this types of tools are forbidden to replace even they are empty
*/
var UNREPLACEBLE_TOOLS = ['image', 'link', 'list', 'instagram', 'twitter', 'embed'],
tool = editor.tools[editor.toolbar.current],
workingNode = editor.content.currentNode,
currentInputIndex = editor.caret.inputIndex,
newBlockContent,
appendCallback,
blockData;
/** Make block from plugin */
newBlockContent = tool.render();
/** information about block */
blockData = {
block: newBlockContent,
type: tool.type,
stretched: false
};
if (workingNode && UNREPLACEBLE_TOOLS.indexOf(workingNode.dataset.tool) === -1 && workingNode.textContent.trim() === '') {
/** Replace current block */
editor.content.switchBlock(workingNode, newBlockContent, tool.type);
} else {
/** Insert new Block from plugin */
editor.content.insertBlock(blockData);
/** increase input index */
currentInputIndex++;
}
/** Fire tool append callback */
appendCallback = tool.appendCallback;
if (appendCallback && typeof appendCallback == 'function') {
appendCallback.call(event);
}
window.setTimeout(function () {
/** Set caret to current block */
editor.caret.setToBlock(currentInputIndex);
}, 10);
/**
* Changing current Node
*/
editor.content.workingNodeChanged();
/**
* Move toolbar when node is changed
*/
editor.toolbar.move();
};
return toolbox;
}({});
/***/ }),
/***/ "./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);
var _selection = __webpack_require__(/*! ../selection */ "./src/components/selection.js");
var _selection2 = _interopRequireDefault(_selection);
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;
this.Editor.Listeners.on(this.nodes.redactor, 'click', function (event) {
return _this4.redactorClicked(event);
}, false);
this.Editor.Listeners.on(document, 'keydown', function (event) {
return _this4.documentKeydown(event);
}, true);
this.Editor.Listeners.on(document, 'click', function (event) {
return _this4.documentClicked(event);
}, false);
}
/**
* All keydowns on document
* @param event
*/
}, {
key: 'documentKeydown',
value: function documentKeydown(event) {
switch (event.keyCode) {
case _.keyCodes.ENTER:
this.enterPressed(event);
break;
default:
this.defaultBehaviour(event);
break;
}
}
/**
* Ignore all other document's keydown events
* @param {KeyboardEvent} event
*/
}, {
key: 'defaultBehaviour',
value: function defaultBehaviour(event) {
var keyDownOnEditor = event.target.closest('.' + this.CSS.editorWrapper);
/**
* Ignore keydowns on document
* clear pointer and close toolbar
*/
if (!keyDownOnEditor) {
/**
* Remove all highlights and remove caret
*/
this.Editor.BlockManager.dropPointer();
/**
* Close Toolbar
*/
this.Editor.Toolbar.close();
}
}
/**
* Enter pressed on document
* @param event
*/
}, {
key: 'enterPressed',
value: function enterPressed(event) {
var hasPointerToBlock = this.Editor.BlockManager.currentBlockIndex >= 0;
/**
* If Selection is out of Editor and document has some selection
*/
if (!_selection2.default.isAtEditor && _selection2.default.anchorNode) {
return;
}
/**
* If there is no selection (caret is not placed) and BlockManager points some to Block
*/
if (hasPointerToBlock && !_selection2.default.anchorNode) {
/**
* Insert initial typed Block
*/
this.Editor.BlockManager.insert();
this.Editor.BlockManager.highlightCurrentNode();
/**
* Move toolbar and show plus button because new Block is empty
*/
this.Editor.Toolbar.move();
this.Editor.Toolbar.plusButton.show();
}
}
/**
* All clicks on document
* @param {MouseEvent} event - Click
*/
}, {
key: 'documentClicked',
value: function documentClicked(event) {
/**
* Close Inline Toolbar when nothing selected
* Do not fire check on clicks at the Inline Toolbar buttons
*/
var clickedOnInlineToolbarButton = event.target.closest('.' + this.Editor.InlineToolbar.CSS.inlineToolbar);
var clickedInsideofEditor = event.target.closest('.' + this.CSS.editorWrapper);
/** Clear highlightings and pointer on BlockManager */
if (!clickedInsideofEditor) {
this.Editor.BlockManager.dropPointer();
this.Editor.Toolbar.close();
}
if (!clickedOnInlineToolbarButton) {
this.Editor.InlineToolbar.handleShowingEvent(event);
}
}
/**
* 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 {
/**
* Renew Current Block
*/
this.Editor.BlockManager.setCurrentBlockByChildNode(clickedNode);
/**
* Highlight Current Node
*/
this.Editor.BlockManager.highlightCurrentNode();
} catch (e) {
/**
* If clicked outside first-level Blocks, set Caret to the last empty Block
*/
this.Editor.Caret.setToTheLastBlock();
}
/**
* Move toolbar and open
*/
this.Editor.Toolbar.move();
this.Editor.Toolbar.open();
/**
* 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"), __webpack_require__(/*! utils */ "./src/components/utils.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;
}
/**
* Editor styles
* @return {{editorWrapper: string, editorZone: string}}
* @constructor
*/
_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
*
* @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 {HTMLElement|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 boundNodes = [
/** the Node in which the selection begins */
selection.anchorNode,
/** the Node in which the selection ends */
selection.focusNode];
/**
* For each selection parent Nodes we try to find target tag [with target class name]
* It would be saved in parentTag variable
*/
boundNodes.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 && !parent.classList.contains(className)) {
continue;
}
/**
* 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',
/**
* Returns window Selection
* {@link https://developer.mozilla.org/ru/docs/Web/API/Window/getSelection}
* @return {Selection}
*/
value: function get() {
return window.getSelection();
}
/**
* Returns selected anchor
* {@link https://developer.mozilla.org/ru/docs/Web/API/Selection/anchorNode}
* @return {Node|null}
*/
}, {
key: 'CSS',
get: function get() {
return {
editorWrapper: 'codex-editor',
editorZone: 'codex-editor__redactor'
};
}
}, {
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;
}
/**
* Check current selection if it is at Editor's zone
* @return {boolean}
*/
}, {
key: 'isAtEditor',
get: function get() {
var selection = Selection.get(),
selectedNode = void 0,
editorZone = false;
/**
* Something selected on document
*/
selectedNode = selection.anchorNode || selection.focusNode;
if (selectedNode && selectedNode.nodeType === Node.TEXT_NODE) {
selectedNode = selectedNode.parentNode;
}
if (selectedNode) {
editorZone = selectedNode.closest('.' + Selection.CSS.editorZone);
}
/**
* Selection is not out of Editor because Editor's wrapper was found
*/
return editorZone && editorZone.nodeType === Node.ELEMENT_NODE;
}
/**
* 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 {\r\n /**\r\n * Selection color\r\n */\r\n --selectionColor: rgba(61,166,239,0.63);\r\n\r\n /**\r\n * Toolbar buttons\r\n */\r\n --bg-light: #eff2f5;\r\n\r\n /**\r\n * All gray texts: placeholders, settings\r\n */\r\n --grayText: #707684;\r\n\r\n /** Blue icons */\r\n --color-active-icon: #388AE5;\r\n\r\n /**\r\n * Block content width\r\n */\r\n --content-width: 650px;\r\n\r\n /**\r\n * Toolbar buttons height and width\r\n */\r\n --toolbar-buttons-size: 34px;\r\n\r\n /**\r\n * Toolbar Plus Button and Toolbox buttons height and width\r\n */\r\n --toolbox-buttons-size: 20px;\r\n\r\n /**\r\n * Confirm deletion bg\r\n */\r\n --color-confirm: #E24A4A;\r\n}\r\n/**\r\n* Editor wrapper\r\n*/\r\n.codex-editor {\r\n position: relative;\r\n box-sizing: border-box;\r\n}\r\n.codex-editor .hide {\r\n display: none;\r\n }\r\n.codex-editor__redactor {\r\n padding-bottom: 300px;\r\n }\r\n.codex-editor svg {\r\n fill: currentColor;\r\n vertical-align: middle;\r\n max-height: 100%;\r\n }\r\n/**\r\n * Set color for native selection\r\n */\r\n::-moz-selection{\r\n background-color: rgba(61,166,239,0.63);\r\n background-color: var(--selectionColor);\r\n}\r\n::selection{\r\n background-color: rgba(61,166,239,0.63);\r\n background-color: var(--selectionColor);\r\n}\r\n/**\r\n * Add placeholder to content editable elements with data attribute\r\n * data-placeholder=\"Hello world!\"\r\n */\r\n[contentEditable=true][data-placeholder]:empty:not(:focus):before{\r\n content: attr(data-placeholder);\r\n color: #707684;\r\n color: var(--grayText);\r\n}\r\n.ce-toolbar {\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n top: 0;\r\n /*opacity: 0;*/\r\n /*visibility: hidden;*/\r\n transition: opacity 100ms ease;\r\n will-change: opacity, transform;\r\n display: none;\r\n}\r\n.ce-toolbar--opened {\r\n display: block;\r\n /*opacity: 1;*/\r\n /*visibility: visible;*/\r\n }\r\n.ce-toolbar__content {\r\n max-width: 650px;\r\n max-width: var(--content-width);\r\n margin: 0 auto;\r\n position: relative;\r\n }\r\n.ce-toolbar__plus {\r\n color: #707684;\r\n color: var(--grayText);\r\n cursor: pointer;\r\n display: inline-block;\r\n width: 20px;\r\n width: var(--toolbox-buttons-size);\r\n height: 20px;\r\n height: var(--toolbox-buttons-size);\r\n line-height: 20px;\r\n line-height: var(--toolbox-buttons-size)\r\n }\r\n.ce-toolbar__plus:not(:last-of-type){\r\n margin-right: 3px;\r\n }\r\n.ce-toolbar__plus:hover {\r\n color: #388AE5;\r\n color: var(--color-active-icon);\r\n }\r\n.ce-toolbar__plus {\r\n\r\n position: absolute;\r\n top: -1px;\r\n left: calc(calc(20px + 10px) * -1);\r\n left: calc(calc(var(--toolbox-buttons-size) + 10px) * -1);\r\n }\r\n.ce-toolbar__plus--hidden {\r\n display: none;\r\n }\r\n/**\r\n * Block actions Zone\r\n * -------------------------\r\n */\r\n.ce-toolbar__actions {\r\n position: absolute;\r\n right: 0;\r\n top: 0;\r\n padding-right: 16px;\r\n }\r\n.ce-toolbar__actions-buttons {\r\n text-align: right;\r\n }\r\n.ce-toolbar__settings-btn {\r\n display: inline-block;\r\n width: 24px;\r\n height: 24px;\r\n color: #707684;\r\n color: var(--grayText);\r\n cursor: pointer;\r\n }\r\n.ce-toolbox {\r\n position: absolute;\r\n visibility: hidden;\r\n transition: opacity 100ms ease;\r\n will-change: opacity;\r\n}\r\n.ce-toolbox--opened {\r\n opacity: 1;\r\n visibility: visible;\r\n }\r\n.ce-toolbox__button {\r\n color: #707684;\r\n color: var(--grayText);\r\n cursor: pointer;\r\n display: inline-block;\r\n width: 20px;\r\n width: var(--toolbox-buttons-size);\r\n height: 20px;\r\n height: var(--toolbox-buttons-size);\r\n line-height: 20px;\r\n line-height: var(--toolbox-buttons-size);\r\n }\r\n.ce-toolbox__button:not(:last-of-type){\r\n margin-right: 3px;\r\n }\r\n.ce-toolbox__button:hover {\r\n color: #388AE5;\r\n color: var(--color-active-icon);\r\n }\r\n.ce-inline-toolbar {\r\n position: absolute;\r\n background-color: #FFFFFF;\r\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\r\n border-radius: 4px;\r\n z-index: 2\r\n}\r\n.ce-inline-toolbar::before {\r\n content: '';\r\n width: 15px;\r\n height: 15px;\r\n position: absolute;\r\n top: -7px;\r\n left: 50%;\r\n margin-left: -7px;\r\n transform: rotate(-45deg);\r\n background-color: #fff;\r\n z-index: -1;\r\n }\r\n.ce-inline-toolbar {\r\n padding: 6px;\r\n transform: translateX(-50%);\r\n display: none;\r\n box-shadow: 0 6px 12px -6px rgba(131, 147, 173, 0.46),\r\n 5px -12px 34px -13px rgba(97, 105, 134, 0.6),\r\n 0 26px 52px 3px rgba(147, 165, 186, 0.24);\r\n}\r\n.ce-inline-toolbar--showed {\r\n display: block;\r\n }\r\n.ce-inline-tool {\r\n display: inline-block;\r\n width: 34px;\r\n height: 34px;\r\n line-height: 34px;\r\n text-align: center;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n border: 0;\r\n outline: none;\r\n background-color: transparent;\r\n vertical-align: bottom;\r\n color: #707684;\r\n color: var(--grayText)\r\n}\r\n.ce-inline-tool:not(:last-of-type){\r\n margin-right: 5px;\r\n }\r\n.ce-inline-tool:hover {\r\n background-color: #eff2f5;\r\n background-color: var(--bg-light);\r\n }\r\n.ce-inline-tool {\r\n line-height: normal;\r\n}\r\n.ce-inline-tool--active {\r\n color: #388AE5;\r\n color: var(--color-active-icon);\r\n }\r\n.ce-inline-tool--link .icon {\r\n margin-top: -2px;\r\n }\r\n.ce-inline-tool--link .icon--unlink {\r\n display: none;\r\n }\r\n.ce-inline-tool--unlink .icon--link {\r\n display: none;\r\n }\r\n.ce-inline-tool--unlink .icon--unlink {\r\n display: inline-block;\r\n }\r\n.ce-inline-tool-input {\r\n background-color: #eff2f5;\r\n background-color: var(--bg-light);\r\n outline: none;\r\n border: 0;\r\n border-radius: 3px;\r\n margin: 6px 0 0;\r\n font-size: 13px;\r\n padding: 8px;\r\n width: 100%;\r\n box-sizing: border-box;\r\n display: none\r\n }\r\n.ce-inline-tool-input::-webkit-input-placeholder {\r\n color: #707684;\r\n color: var(--grayText);\r\n }\r\n.ce-inline-tool-input:-ms-input-placeholder {\r\n color: #707684;\r\n color: var(--grayText);\r\n }\r\n.ce-inline-tool-input::placeholder {\r\n color: #707684;\r\n color: var(--grayText);\r\n }\r\n.ce-inline-tool-input--showed {\r\n display: block;\r\n }\r\n.ce-settings {\r\n position: absolute;\r\n background-color: #FFFFFF;\r\n box-shadow: 0 8px 23px -6px rgba(21,40,54,0.31), 22px -14px 34px -18px rgba(33,48,73,0.26);\r\n border-radius: 4px;\r\n z-index: 2\r\n}\r\n.ce-settings::before {\r\n content: '';\r\n width: 15px;\r\n height: 15px;\r\n position: absolute;\r\n top: -7px;\r\n left: 50%;\r\n margin-left: -7px;\r\n transform: rotate(-45deg);\r\n background-color: #fff;\r\n z-index: -1;\r\n }\r\n.ce-settings {\r\n right: 5px;\r\n top: 35px;\r\n min-width: 124px\r\n}\r\n.ce-settings::before{\r\n left: auto;\r\n right: 12px;\r\n }\r\n.ce-settings {\r\n\r\n display: none;\r\n}\r\n.ce-settings--opened {\r\n display: block;\r\n }\r\n.ce-settings__plugin-zone:not(:empty){\r\n padding: 6px 6px 0;\r\n }\r\n.ce-settings__default-zone:not(:empty){\r\n padding: 6px;\r\n }\r\n.ce-settings__button {\r\n display: inline-block;\r\n width: 34px;\r\n height: 34px;\r\n line-height: 34px;\r\n text-align: center;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n border: 0;\r\n outline: none;\r\n background-color: transparent;\r\n vertical-align: bottom;\r\n color: #707684;\r\n color: var(--grayText)\r\n }\r\n.ce-settings__button:not(:last-of-type){\r\n margin-right: 5px;\r\n }\r\n.ce-settings__button:hover {\r\n background-color: #eff2f5;\r\n background-color: var(--bg-light);\r\n }\r\n.ce-settings__button--active {\r\n color: #388AE5;\r\n color: var(--color-active-icon);\r\n }\r\n.ce-settings__button--disabled {\r\n cursor: not-allowed !important;\r\n opacity: .3;\r\n }\r\n.ce-settings__button--selected {\r\n color: #388AE5;\r\n color: var(--color-active-icon);\r\n }\r\n.ce-settings__button--delete {\r\n transition: background-color 300ms ease;\r\n will-change: background-color;\r\n }\r\n.ce-settings__button--delete .icon {\r\n transition: transform 200ms ease-out;\r\n will-change: transform;\r\n }\r\n.ce-settings__button--confirm {\r\n background-color: #E24A4A;\r\n background-color: var(--color-confirm);\r\n color: #fff\r\n }\r\n.ce-settings__button--confirm:hover {\r\n background-color: rgb(213, 74, 74) !important;\r\n background-color: rgb(213, 74, 74) !important;\r\n }\r\n.ce-settings__button--confirm .icon {\r\n transform: rotate(90deg);\r\n }\r\n.ce-block:first-of-type {\r\n margin-top: 0;\r\n }\r\n.ce-block--selected {\r\n background-image: linear-gradient(17deg, rgba(243, 248, 255, 0.03) 63.45%, rgba(207, 214, 229, 0.27) 98%);\r\n border-radius: 3px;\r\n }\r\n.ce-block__content {\r\n max-width: 650px;\r\n max-width: var(--content-width);\r\n margin: 0 auto;\r\n }\r\n.wobble {\r\n animation-name: wobble;\r\n animation-duration: 400ms;\r\n}\r\n/**\r\n * @author Nick Pettit - https://github.com/nickpettit/glide\r\n */\r\n@keyframes wobble {\r\n from {\r\n transform: translate3d(0, 0, 0);\r\n }\r\n\r\n 15% {\r\n transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -5deg);\r\n }\r\n\r\n 30% {\r\n transform: translate3d(2%, 0, 0) rotate3d(0, 0, 1, 3deg);\r\n }\r\n\r\n 45% {\r\n transform: translate3d(-3%, 0, 0) rotate3d(0, 0, 1, -3deg);\r\n }\r\n\r\n 60% {\r\n transform: translate3d(2%, 0, 0) rotate3d(0, 0, 1, 2deg);\r\n }\r\n\r\n 75% {\r\n transform: translate3d(-1%, 0, 0) rotate3d(0, 0, 1, -1deg);\r\n }\r\n\r\n to {\r\n transform: translate3d(0, 0, 0);\r\n }\r\n}\r\n", ""]);
// exports
/***/ })
/******/ });
});
//# sourceMappingURL=codex-editor.js.map