Caret module: initial

This commit is contained in:
Murod Khaydarov 2017-12-27 08:47:30 +03:00
commit c2acc25825
9 changed files with 811 additions and 52 deletions

View file

@ -199,6 +199,15 @@ var Util = function () {
}
}
/**
* Returns basic keycodes as constants
* @return {{}}
*/
}, {
key: 'sequence',
/**
* @typedef {Object} ChainData
* @property {Object} data - data that will be passed to the success or fallback
@ -214,9 +223,6 @@ var Util = function () {
*
* @return {Promise}
*/
}, {
key: 'sequence',
value: function sequence(chains) {
var success = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
var fallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
@ -315,6 +321,57 @@ var Util = function () {
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';
}
}, {
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
};
}
/**
* Returns basic nodetypes as contants
* @return {{TAG: number, TEXT: number, COMMENT: number, DOCUMENT_FRAGMENT: number}}
*/
}, {
key: 'nodeTypes',
get: function get() {
return {
TAG: 1,
TEXT: 3,
COMMENT: 8,
DOCUMENT_FRAGMENT: 11
};
}
}]);
return Util;
@ -345,7 +402,7 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* DOM manupulations helper
* DOM manipulations helper
*/
var Dom = function () {
function Dom() {
@ -388,6 +445,20 @@ var Dom = function () {
return el;
}
/**
* Creates text Node with content
*
* @param {String} content - text content
* @return {Text}
*/
}, {
key: 'text',
value: function text(content) {
return document.createTextNode(content);
}
/**
* Append one or several elements to the parent
*
@ -451,6 +522,52 @@ var Dom = function () {
return el.querySelectorAll(selector);
}
/**
* Search for deepest node
*
* @param {Element} node - start Node
* @param {Boolean} atLast - find last text node
* @return {*}
*/
}, {
key: 'getDeepestTextNode',
value: function getDeepestTextNode(node) {
var atLast = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (node.childNodes.length === 0) {
/**
* We need to return empty text node
* But caret will not be placed in empty textNode, so we need textNode with zero-width char
*/
if (this.isElement(node)) {
/** and it is not native input */
if (!this.isNativeInput(node)) {
var emptyTextNode = this.text('\u200B');
node.appendChild(emptyTextNode);
}
}
return node;
}
var childsLength = node.childNodes.length,
last = childsLength - 1;
if (atLast) {
return this.getDeepestTextNode(node.childNodes[last], atLast);
} else {
return this.getDeepestTextNode(node.childNodes[0], false);
}
}
/**
* Check if object is DOM node
*
@ -464,6 +581,96 @@ var Dom = function () {
return node && (typeof node === 'undefined' ? 'undefined' : _typeof(node)) === 'object' && node.nodeType && node.nodeType === Node.ELEMENT_NODE;
}
/**
* Checks target if it is native input
* @param {Element|*} target - HTML element or string
* @return {boolean}
*/
}, {
key: 'isNativeInput',
value: function isNativeInput(target) {
var nativeInputs = ['INPUT', 'TEXTAREA'];
return nativeInputs.indexOf(target.tagName) !== -1;
}
}, {
key: 'isEmpty',
value: function isEmpty(node) {
var _this = this;
var treeWalker = [],
stack = [];
treeWalker.push(node);
while (treeWalker.length > 0) {
if (node && node.childNodes.length === 0) {
stack.push(node);
}
while (node && node.nextSibling) {
node = node.nextSibling;
if (!node) continue;
if (node.childNodes.length === 0) {
stack.push(node);
}
treeWalker.push(node);
}
node = treeWalker.shift();
if (!node) continue;
node = node.firstChild;
treeWalker.push(node);
}
var isEmpty = true;
stack.forEach(function (node) {
if (_this.isElement(node)) {
if (_this.isNativeInput(node)) {
node = node.value;
if (node.trim()) {
isEmpty = false;
}
} else {
node = node.textContent.replace('\u200B', '');
if (node.trim()) {
isEmpty = false;
}
}
} else {
node = node.textContent.replace('\u200B', '');
if (node.trim()) {
isEmpty = false;
}
}
});
return isEmpty;
}
}]);
return Dom;
@ -1263,7 +1470,7 @@ webpackContext.id = 6;
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(Module, $, _) {
/* WEBPACK VAR INJECTION */(function(Module, _, $) {
Object.defineProperty(exports, "__esModule", {
value: true
@ -1382,6 +1589,8 @@ var BlockManager = function (_Module) {
var toolInstance = this.Editor.Tools.construct(toolName, data),
block = new _block2.default(toolName, toolInstance);
this.bindEvents(block);
/**
* Apply callback before inserting html
*/
@ -1390,6 +1599,73 @@ var BlockManager = function (_Module) {
return block;
}
/**
* Bind Events
* @param {Object} block
*/
}, {
key: 'bindEvents',
value: function bindEvents(block) {
var _this3 = this;
/** contentNode click handler */
block.wrapper.addEventListener('click', function (event) {
return _this3.wrapperClicked(event);
}, false);
/** keydown on block */
block.pluginsContent.addEventListener('keydown', function (event) {
return _this3.keyDownOnBlock(event);
}, false);
}
/**
* Highlight clicked block
* @param {MouseEvent} event
*/
}, {
key: 'wrapperClicked',
value: function wrapperClicked(event) {
this.setCurrentBlockByChildNode(event.target);
}
/**
*
* @param {MouseEvent} event
*/
}, {
key: 'keyDownOnBlock',
value: function keyDownOnBlock(event) {
switch (event.keyCode) {
case _.keyCodes.ENTER:
this.enterPressedOnPluginsContent(event);
break;
case _.keyCodes.DOWN:
case _.keyCodes.RIGHT:
this.blockRightOrDownArrowPressed(event);
break;
}
}
/**
*
* @param event
*/
}, {
key: 'blockRightOrDownArrowPressed',
value: function blockRightOrDownArrowPressed(event) {
console.log(this.getNextBlock());
}
/**
* Insert new block into _blocks
*
@ -1406,6 +1682,8 @@ var BlockManager = function (_Module) {
var block = this.composeBlock(toolName, data);
this._blocks[++this.currentBlockIndex] = block;
this.Editor.Caret.set(block.pluginsContent);
}
/**
@ -1426,6 +1704,42 @@ var BlockManager = function (_Module) {
this._blocks.insert(this.currentBlockIndex, block, true);
}
/**
*
* @return {*}
*/
}, {
key: 'getLastBlock',
value: function getLastBlock() {
return this._blocks[this._blocks.length - 1];
}
/**
*
* @param index
* @return {*}
*/
}, {
key: 'getBlockByIndex',
value: function getBlockByIndex(index) {
return this._blocks[index];
}
}, {
key: 'getNextBlock',
value: function getNextBlock() {
if (this.currentBlockIndex + 1 > this._blocks.length - 1) {
return null;
}
return this._blocks[this.currentBlockIndex + 1];
}
/**
* Get Block instance by html element
*
@ -1554,6 +1868,13 @@ var BlockManager = function (_Module) {
return BlockManager;
}(Module);
BlockManager.displayName = 'BlockManager';
exports.default = BlockManager;
var BlockMethods = function BlockMethods() {
_classCallCheck(this, BlockMethods);
};
/**
* @class Blocks
* @classdesc Class to work with Block instances array
@ -1565,8 +1886,7 @@ var BlockManager = function (_Module) {
*/
BlockManager.displayName = 'BlockManager';
exports.default = BlockManager;
BlockMethods.displayName = 'BlockMethods';
var Blocks = function () {
@ -1787,14 +2107,14 @@ var Blocks = function () {
Blocks.displayName = 'Blocks';
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(2), __webpack_require__(1)))
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(1), __webpack_require__(2)))
/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(Module) {
/* WEBPACK VAR INJECTION */(function(Module, $) {
Object.defineProperty(exports, "__esModule", {
value: true
@ -1829,14 +2149,52 @@ var Caret = function (_Module) {
}
/**
* Set Caret to the last Block
*
* If last block is not empty, append another empty block
* Creates Document Range and sets caret to the element.
* @param {Element} element - target node.
* @param {Number} offset - offset
*/
_createClass(Caret, [{
key: 'setToTheLastBlock',
key: "set",
value: function set(element) {
var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
/** If Element is INPUT */
if ($.isNativeInput(element)) {
element.focus();
return;
}
var nodeToSet = $.getDeepestTextNode(element, true);
/** if found deepest node is native input */
if ($.isNativeInput(nodeToSet)) {
nodeToSet.focus();
return;
}
var range = document.createRange(),
selection = window.getSelection();
range.setStart(nodeToSet, offset);
range.setEnd(nodeToSet, offset);
selection.removeAllRanges();
selection.addRange(range);
}
}, {
key: "setToTheLastBlock",
/**
* Set Caret to the last Block
*
* If last block is not empty, append another empty block
*/
value: function setToTheLastBlock() {
var blocks = this.Editor.BlockManager.blocks,
@ -1902,31 +2260,31 @@ var Caret = function (_Module) {
// }
}
/**
* Set caret to the passed Node
* @param {Element} node - content-editable Element
*/
// /**
// * Set caret to the passed Node
// * @param {Element} node - content-editable Element
// */
// set(node) {
//
// /**
// * @todo add working with Selection
// * tmp: work with textContent
// */
//
// node.textContent += '|';
//
// }
}, {
key: 'set',
value: function set(node) {
/**
* @todo add working with Selection
* tmp: work with textContent
*/
node.textContent += '|';
}
}]);
return Caret;
}(Module);
Caret.displayName = 'Caret';
Caret.displayName = "Caret";
exports.default = Caret;
module.exports = exports['default'];
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)))
module.exports = exports["default"];
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0), __webpack_require__(2)))
/***/ }),
/* 9 */
@ -3987,6 +4345,13 @@ var UI = function (_Module) {
var clickedNode = event.target;
console.log('click', clickedNode);
if (clickedNode.classList.contains(this.CSS.editorZone)) {
this.clickedOnRedactorZone(event);
return;
}
/**
* Select clicked Block as Current
*/
@ -4106,6 +4471,24 @@ var UI = function (_Module) {
this.Editor.Toolbar.plusButton.show();
}
}
}, {
key: 'clickedOnRedactorZone',
value: function clickedOnRedactorZone(event) {
var lastBlock = this.Editor.BlockManager.getLastBlock(),
pluginsContent = lastBlock.pluginsContent;
/**
* If last block has text content, then insert new Block after
*/
if (!$.isEmpty(pluginsContent)) {
this.Editor.BlockManager.insert(this.config.initialBlock, {});
} else {
this.Editor.Caret.set(pluginsContent);
}
}
}, {
key: 'CSS',
get: function get() {
@ -4350,7 +4733,7 @@ exports = module.exports = __webpack_require__(19)(undefined);
// module
exports.push([module.i, ":root {\n\n /**\n * Toolbar buttons\n */\n\n /**\n * Block content width\n */\n\n /**\n * Toolbar Plus Button and Toolbox buttons height and width\n */\n\n}\n/**\n* Editor wrapper\n*/\n.codex-editor {\n position: relative;\n border: 1px solid #ccc;\n padding: 10px;\n box-sizing: border-box;\n}\n.codex-editor .hide {\n display: none;\n }\n.codex-editor__redactor {\n padding-bottom: 300px;\n }\n.ce-toolbar {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n opacity: 0;\n visibility: hidden;\n transition: opacity 100ms ease;\n will-change: opacity, transform;\n}\n.ce-toolbar--opened {\n opacity: 1;\n visibility: visible;\n }\n.ce-toolbar__content {\n max-width: 650px;\n margin: 0 auto;\n position: relative;\n }\n.ce-toolbar__plus {\n position: absolute;\n left: calc(-34px - 10px);\n display: inline-block;\n background-color: #eff2f5;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n border-radius: 50%\n }\n.ce-toolbar__plus::after {\n content: '+';\n font-size: 26px;\n display: block;\n margin-top: -2px;\n margin-right: -2px;\n\n}\n.ce-toolbar__plus--hidden {\n display: none;\n\n}\n.ce-toolbox {\n visibility: hidden;\n transition: opacity 100ms ease;\n will-change: opacity;\n}\n.ce-toolbox--opened {\n opacity: 1;\n visibility: visible;\n }\n.ce-toolbox__button {\n display: inline-block;\n list-style: none;\n margin: 0;\n background: #eff2f5;\n width: 34px;\n height: 34px;\n border-radius: 30px;\n overflow: hidden;\n text-align: center;\n line-height: 34px\n }\n.ce-toolbox__button::before {\n content: attr(title);\n font-size: 22px;\n font-weight: 500;\n letter-spacing: 1em;\n -webkit-font-feature-settings: \"smcp\", \"c2sc\";\n font-feature-settings: \"smcp\", \"c2sc\";\n font-variant-caps: all-small-caps;\n padding-left: 11.5px;\n margin-top: -1px;\n display: inline-block;\n\n}\n.ce-block {\n border: 1px dotted #ccc;\n margin: 2px 0;\n}\n.ce-block--selected {\n background-color: #eff2f5;\n }\n.ce-block__content {\n max-width: 650px;\n margin: 0 auto;\n }\n", ""]);
exports.push([module.i, ":root {\n\n /**\n * Toolbar buttons\n */\n\n /**\n * Block content width\n */\n\n /**\n * Toolbar Plus Button and Toolbox buttons height and width\n */\n\n}\n/**\n* Editor wrapper\n*/\n.codex-editor {\n position: relative;\n border: 1px solid #ccc;\n padding: 10px;\n box-sizing: border-box;\n}\n.codex-editor .hide {\n display: none;\n }\n.codex-editor__redactor {\n padding-bottom: 300px;\n }\n.ce-toolbar {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n /*opacity: 0;*/\n /*visibility: hidden;*/\n transition: opacity 100ms ease;\n will-change: opacity, transform;\n display: none;\n}\n.ce-toolbar--opened {\n display: block;\n /*opacity: 1;*/\n /*visibility: visible;*/\n }\n.ce-toolbar__content {\n max-width: 650px;\n margin: 0 auto;\n position: relative;\n }\n.ce-toolbar__plus {\n position: absolute;\n left: calc(-34px - 10px);\n display: inline-block;\n background-color: #eff2f5;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n border-radius: 50%\n }\n.ce-toolbar__plus::after {\n content: '+';\n font-size: 26px;\n display: block;\n margin-top: -2px;\n margin-right: -2px;\n\n}\n.ce-toolbar__plus--hidden {\n display: none;\n\n}\n.ce-toolbox {\n visibility: hidden;\n transition: opacity 100ms ease;\n will-change: opacity;\n}\n.ce-toolbox--opened {\n opacity: 1;\n visibility: visible;\n }\n.ce-toolbox__button {\n display: inline-block;\n list-style: none;\n margin: 0;\n background: #eff2f5;\n width: 34px;\n height: 34px;\n border-radius: 30px;\n overflow: hidden;\n text-align: center;\n line-height: 34px\n }\n.ce-toolbox__button::before {\n content: attr(title);\n font-size: 22px;\n font-weight: 500;\n letter-spacing: 1em;\n -webkit-font-feature-settings: \"smcp\", \"c2sc\";\n font-feature-settings: \"smcp\", \"c2sc\";\n font-variant-caps: all-small-caps;\n padding-left: 11.5px;\n margin-top: -1px;\n display: inline-block;\n\n}\n.ce-block {\n border: 1px dotted #ccc;\n margin: 2px 0;\n}\n.ce-block--selected {\n background-color: #eff2f5;\n }\n.ce-block__content {\n max-width: 650px;\n margin: 0 auto;\n }\n", ""]);
// exports

File diff suppressed because one or more lines are too long

View file

@ -82,7 +82,7 @@
{
type : 'text',
data : {
text : 'Пишите нам на team@ifmo.su'
text : '<span><textarea></textarea></span><p><b></b></p><strong></strong><i><span></span></i>'
}
},
]

View file

@ -1,5 +1,5 @@
/**
* DOM manupulations helper
* DOM manipulations helper
*/
export default class Dom {
@ -35,6 +35,18 @@ export default class Dom {
}
/**
* Creates text Node with content
*
* @param {String} content - text content
* @return {Text}
*/
static text(content) {
return document.createTextNode(content);
}
/**
* Append one or several elements to the parent
*
@ -86,6 +98,54 @@ export default class Dom {
}
/**
* Search for deepest node
*
* @param {Element} node - start Node
* @param {Boolean} atLast - find last text node
* @return {*}
*/
static getDeepestTextNode(node, atLast = false) {
if (node.childNodes.length === 0) {
/**
* We need to return empty text node
* But caret will not be placed in empty textNode, so we need textNode with zero-width char
*/
if (this.isElement(node)) {
/** and it is not native input */
if (!this.isNativeInput(node)) {
let emptyTextNode = this.text('\u200B');
node.appendChild(emptyTextNode);
}
}
return node;
}
let childsLength = node.childNodes.length,
last = childsLength - 1;
if (atLast) {
return this.getDeepestTextNode(node.childNodes[last], atLast);
} else {
return this.getDeepestTextNode(node.childNodes[0], false);
}
}
/**
* Check if object is DOM node
*
@ -98,4 +158,106 @@ export default class Dom {
}
/**
* Checks target if it is native input
* @param {Element|*} target - HTML element or string
* @return {boolean}
*/
static isNativeInput(target) {
let nativeInputs = [
'INPUT',
'TEXTAREA'
];
return nativeInputs.indexOf(target.tagName) !== -1;
}
static isEmpty(node) {
let treeWalker = [],
stack = [];
treeWalker.push(node);
while ( treeWalker.length > 0 ) {
if (node && node.childNodes.length === 0) {
stack.push(node);
}
while ( node && node.nextSibling ) {
node = node.nextSibling;
if (!node) continue;
if (node.childNodes.length === 0) {
stack.push(node);
}
treeWalker.push(node);
}
node = treeWalker.shift();
if (!node) continue;
node = node.firstChild;
treeWalker.push(node);
}
let isEmpty = true;
stack.forEach( (node) => {
if ( this.isElement(node) ) {
if ( this.isNativeInput(node) ) {
node = node.value;
if ( node.trim() ) {
isEmpty = false;
}
} else {
node = node.textContent.replace('\u200B', '');
if ( node.trim() ) {
isEmpty = false;
}
}
} else {
node = node.textContent.replace('\u200B', '');
if ( node.trim() ) {
isEmpty = false;
}
}
});
return isEmpty;
}
};

View file

@ -90,6 +90,8 @@ export default class BlockManager extends Module {
let toolInstance = this.Editor.Tools.construct(toolName, data),
block = new Block(toolName, toolInstance);
this.bindEvents(block);
/**
* Apply callback before inserting html
*/
@ -99,6 +101,60 @@ export default class BlockManager extends Module {
}
/**
* Bind Events
* @param {Object} block
*/
bindEvents(block) {
/** contentNode click handler */
block.wrapper.addEventListener('click', (event) => this.wrapperClicked(event), false);
/** keydown on block */
block.pluginsContent.addEventListener('keydown', (event) => this.keyDownOnBlock(event), false);
}
/**
* Highlight clicked block
* @param {MouseEvent} event
*/
wrapperClicked(event) {
this.setCurrentBlockByChildNode(event.target);
}
/**
*
* @param {MouseEvent} event
*/
keyDownOnBlock(event) {
switch(event.keyCode) {
case _.keyCodes.ENTER:
this.enterPressedOnPluginsContent(event);
break;
case _.keyCodes.DOWN:
case _.keyCodes.RIGHT:
this.blockRightOrDownArrowPressed(event);
break;
}
}
/**
*
* @param event
*/
blockRightOrDownArrowPressed(event) {
console.log(this.getNextBlock());
}
/**
* Insert new block into _blocks
*
@ -112,6 +168,8 @@ export default class BlockManager extends Module {
this._blocks[++this.currentBlockIndex] = block;
this.Editor.Caret.set(block.pluginsContent);
}
/**
@ -128,6 +186,39 @@ export default class BlockManager extends Module {
}
/**
*
* @return {*}
*/
getLastBlock() {
return this._blocks[this._blocks.length - 1];
}
/**
*
* @param index
* @return {*}
*/
getBlockByIndex(index) {
return this._blocks[index];
}
getNextBlock() {
if (this.currentBlockIndex + 1 > this._blocks.length - 1) {
return null;
}
return this._blocks[this.currentBlockIndex + 1];
}
/**
* Get Block instance by html element
*
@ -244,6 +335,12 @@ export default class BlockManager extends Module {
}
}
class BlockMethods {
}
/**

View file

@ -15,6 +15,42 @@ export default class Caret extends Module {
}
/**
* Creates Document Range and sets caret to the element.
* @param {Element} element - target node.
* @param {Number} offset - offset
*/
set( element, offset = 0) {
/** If Element is INPUT */
if ($.isNativeInput(element)) {
element.focus();
return;
}
let nodeToSet = $.getDeepestTextNode(element, true);
/** if found deepest node is native input */
if ($.isNativeInput(nodeToSet)) {
nodeToSet.focus();
return;
}
let range = document.createRange(),
selection = window.getSelection();
range.setStart(nodeToSet, offset);
range.setEnd(nodeToSet, offset);
selection.removeAllRanges();
selection.addRange(range);
};
/**
* Set Caret to the last Block
*
@ -90,20 +126,20 @@ export default class Caret extends Module {
}
/**
* Set caret to the passed Node
* @param {Element} node - content-editable Element
*/
set(node) {
/**
* @todo add working with Selection
* tmp: work with textContent
*/
node.textContent += '|';
}
// /**
// * Set caret to the passed Node
// * @param {Element} node - content-editable Element
// */
// set(node) {
//
// /**
// * @todo add working with Selection
// * tmp: work with textContent
// */
//
// node.textContent += '|';
//
// }
}

View file

@ -224,6 +224,14 @@ export default class UI extends Module {
let clickedNode = event.target;
console.log('click', clickedNode);
if ( clickedNode.classList.contains(this.CSS.editorZone) ) {
this.clickedOnRedactorZone(event);
return;
}
/**
* Select clicked Block as Current
*/
@ -352,6 +360,26 @@ export default class UI extends Module {
}
clickedOnRedactorZone(event) {
let lastBlock = this.Editor.BlockManager.getLastBlock(),
pluginsContent = lastBlock.pluginsContent;
/**
* If last block has text content, then insert new Block after
*/
if (!$.isEmpty(pluginsContent)) {
this.Editor.BlockManager.insert(this.config.initialBlock, {});
} else {
this.Editor.Caret.set(pluginsContent);
}
}
}
// /**

View file

@ -40,6 +40,46 @@ export default class Util {
}
/**
* Returns basic keycodes as constants
* @return {{}}
*/
static get keyCodes() {
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
};
}
/**
* Returns basic nodetypes as contants
* @return {{TAG: number, TEXT: number, COMMENT: number, DOCUMENT_FRAGMENT: number}}
*/
static get nodeTypes() {
return {
TAG : 1,
TEXT : 3,
COMMENT : 8,
DOCUMENT_FRAGMENT: 11
};
}
/**
* @typedef {Object} ChainData
* @property {Object} data - data that will be passed to the success or fallback
@ -157,4 +197,15 @@ export default class Util {
}
/**
* Check if passed element is contenteditable
* @param element
* @return {boolean}
*/
static isContentEditable(element) {
return element.contentEditable === 'true';
}
};

View file

@ -3,14 +3,16 @@
left: 0;
right: 0;
top: 0;
opacity: 0;
visibility: hidden;
/*opacity: 0;*/
/*visibility: hidden;*/
transition: opacity 100ms ease;
will-change: opacity, transform;
display: none;
&--opened {
opacity: 1;
visibility: visible;
display: block;
/*opacity: 1;*/
/*visibility: visible;*/
}
&__content {