UNPKG

upfront-editable

Version:
264 lines (214 loc) 8.23 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getHost = getHost; exports.getNodeIndex = getNodeIndex; exports.isVoid = isVoid; exports.isVoidTextNode = isVoidTextNode; exports.isWhitespaceOnly = isWhitespaceOnly; exports.isLinebreak = isLinebreak; exports.lastOffsetWithContent = lastOffsetWithContent; exports.isBeginningOfHost = isBeginningOfHost; exports.isEndOfHost = isEndOfHost; exports.isStartOffset = isStartOffset; exports.isEndOffset = isEndOffset; exports.isTextEndOfHost = isTextEndOfHost; exports.isTextEndOffset = isTextEndOffset; exports.isSameNode = isSameNode; exports.latestChild = latestChild; exports.isDocumentFragmentWithoutChildren = isDocumentFragmentWithoutChildren; exports.isInlineElement = isInlineElement; var _jquery = _interopRequireDefault(require("jquery")); var string = _interopRequireWildcard(require("./util/string")); var nodeType = _interopRequireWildcard(require("./node-type")); var _config = _interopRequireDefault(require("./config")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * The parser module provides helper methods to parse html-chunks * manipulations and helpers for common tasks. * Provides DOM lookup helpers * * @module core * @submodule parser */ /** * Get the editableJS host block of a node. * * @method getHost * @param {DOM Node} * @return {DOM Node} */ function getHost(node) { var editableSelector = ".".concat(_config["default"].editableClass); var hostNode = (0, _jquery["default"])(node).closest(editableSelector); return hostNode[0]; } /** * Get the index of a node so that * parent.childNodes[ getNodeIndex(node) ] would return the node again. * * @method getNodeIndex * @param {HTMLElement} */ function getNodeIndex(node) { var index = 0; while ((node = node.previousSibling) !== null) { index++; } return index; } /** * Check if node contains text or element nodes * whitespace counts too! * * @method isVoid * @param {HTMLElement} */ function isVoid(node) { return Array.from(node.childNodes).every(function (child) { if (child.nodeType === nodeType.textNode && !isVoidTextNode(child)) { return false; } if (child.nodeType === nodeType.elementNode) { return false; } return true; }); } /** * Check if node is a text node and completely empty without any whitespace * * @method isVoidTextNode * @param {HTMLElement} */ function isVoidTextNode(node) { return node.nodeType === nodeType.textNode && !node.nodeValue; } /** * Check if node is a text node and contains nothing but whitespace * * @method isWhitespaceOnly * @param {HTMLElement} */ function isWhitespaceOnly(node) { return node.nodeType === nodeType.textNode && lastOffsetWithContent(node) === 0; } function isLinebreak(node) { return node.nodeType === nodeType.elementNode && node.tagName === 'BR'; } /** * Returns the last offset where the cursor can be positioned to * be at the visible end of its container. * Currently works only for empty text nodes (not empty tags) * * @method isWhitespaceOnly * @param {HTMLElement} */ function lastOffsetWithContent(elem) { if (elem.nodeType === nodeType.textNode) return string.trimRight(elem.nodeValue).length; var lastOffset = 0; Array.from(elem.childNodes).reverse().every(function (node, index, nodes) { if (isWhitespaceOnly(node) || isLinebreak(node)) return true; lastOffset = nodes.length - index; return false; }); return lastOffset; } function isBeginningOfHost(host, container, offset) { if (container === host) return isStartOffset(container, offset); if (isStartOffset(container, offset)) { // The index of the element simulates a range offset // right before the element. var offsetInParent = getNodeIndex(container); return isBeginningOfHost(host, container.parentNode, offsetInParent); } return false; } function isEndOfHost(host, container, offset) { if (container === host) return isEndOffset(container, offset); if (isEndOffset(container, offset)) { // The index of the element plus one simulates a range offset // right after the element. var offsetInParent = getNodeIndex(container) + 1; return isEndOfHost(host, container.parentNode, offsetInParent); } return false; } function isStartOffset(container, offset) { if (container.nodeType === nodeType.textNode) return offset === 0; if (container.childNodes.length === 0) return true; return container.childNodes[offset] === container.firstChild; } function isEndOffset(container, offset) { if (container.nodeType === nodeType.textNode) return offset === container.length; if (container.childNodes.length === 0) return true; if (offset > 0) return container.childNodes[offset - 1] === container.lastChild; return false; } function isTextEndOfHost(host, container, offset) { if (container === host) return isTextEndOffset(container, offset); if (isTextEndOffset(container, offset)) { // The index of the element plus one simulates a range offset // right after the element. var offsetInParent = getNodeIndex(container) + 1; return isTextEndOfHost(host, container.parentNode, offsetInParent); } return false; } function isTextEndOffset(container, offset) { if (container.nodeType === nodeType.textNode) { var text = string.trimRight(container.nodeValue); return offset >= text.length; } if (container.childNodes.length === 0) return true; return offset >= lastOffsetWithContent(container); } function isSameNode(target, source) { var i, len, attr; if (target.nodeType !== source.nodeType) return false; if (target.nodeName !== source.nodeName) return false; for (i = 0, len = target.attributes.length; i < len; i++) { attr = target.attributes[i]; if (source.getAttribute(attr.name) !== attr.value) return false; } return true; } /** * Return the deepest last child of a node. * * @method latestChild * @param {HTMLElement} container The container to iterate on. * @return {HTMLElement} The deepest last child in the container. */ function latestChild(container) { return container.lastChild ? latestChild(container.lastChild) : container; } /** * Checks if a documentFragment has no children. * Fragments without children can cause errors if inserted into ranges. * * @method isDocumentFragmentWithoutChildren * @param {HTMLElement} DOM node. * @return {Boolean} */ function isDocumentFragmentWithoutChildren(fragment) { return fragment && fragment.nodeType === nodeType.documentFragmentNode && fragment.childNodes.length === 0; } /** * Determine if an element behaves like an inline element. */ function isInlineElement(window, element) { var styles = element.currentStyle || window.getComputedStyle(element, ''); var display = styles.display; switch (display) { case 'inline': case 'inline-block': return true; default: return false; } }