UNPKG

upfront-editable

Version:
272 lines (219 loc) 7.64 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _from = require('babel-runtime/core-js/array/from'); var _from2 = _interopRequireDefault(_from); 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 = require('jquery'); var _jquery2 = _interopRequireDefault(_jquery); var _string = require('./util/string'); var string = _interopRequireWildcard(_string); var _nodeType = require('./node-type'); var nodeType = _interopRequireWildcard(_nodeType); var _config = require('./config'); var config = _interopRequireWildcard(_config); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * 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 = '.' + config.editableClass; var hostNode = (0, _jquery2.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) { var _this = this; return (0, _from2.default)(node.childNodes).every(function (child) { if (child.nodeType === nodeType.textNode && !_this.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 && this.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(node) { var _this2 = this; if (node.nodeType === nodeType.textNode) return string.trimRight(node.nodeValue).length; var lastOffset = 0; (0, _from2.default)(node.childNodes).reverse().every(function (node, index, nodes) { if (_this2.isWhitespaceOnly(node) || _this2.isLinebreak(node)) return true; lastOffset = nodes.length - index; return false; }); return lastOffset; } function isBeginningOfHost(host, container, offset) { if (container === host) return this.isStartOffset(container, offset); if (this.isStartOffset(container, offset)) { // The index of the element simulates a range offset // right before the element. var offsetInParent = this.getNodeIndex(container); return this.isBeginningOfHost(host, container.parentNode, offsetInParent); } return false; } function isEndOfHost(host, container, offset) { if (container === host) return this.isEndOffset(container, offset); if (this.isEndOffset(container, offset)) { // The index of the element plus one simulates a range offset // right after the element. var offsetInParent = this.getNodeIndex(container) + 1; return this.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 this.isTextEndOffset(container, offset); if (this.isTextEndOffset(container, offset)) { // The index of the element plus one simulates a range offset // right after the element. var offsetInParent = this.getNodeIndex(container) + 1; return this.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 >= this.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 ? this.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; } }