UNPKG

upfront-editable

Version:
119 lines (98 loc) 3.48 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.binaryCursorSearch = binaryCursorSearch; var _element = require("./element"); /** * This is a binary search algorithm implementation aimed at finding * a character offset position in a consecutive strings of characters * over several lines. * * Refer to this page in order to learn more about binary search: * https://en.wikipedia.org/wiki/Binary_search_algorithm * * @returns {object} * - object with boolean `wasFound` indicating if the binary search found an offset and `offset` to indicate the actual character offset */ function binaryCursorSearch(_ref) { var host = _ref.host, requiredOnFirstLine = _ref.requiredOnFirstLine, requiredOnLastLine = _ref.requiredOnLastLine, positionX = _ref.positionX; var hostRange = host.ownerDocument.createRange(); hostRange.selectNodeContents(host); var hostCoords = hostRange.getBoundingClientRect(); var totalCharCount = (0, _element.getTotalCharCount)(host); var textNodes = (0, _element.textNodesUnder)(host); // early terminate on empty editables if (totalCharCount === 0) return { wasFound: false }; var data = { currentOffset: Math.floor(totalCharCount / 2), leftLimit: 0, rightLimit: totalCharCount }; var offset = data.currentOffset; var distance; var safety = 20; while (data.leftLimit < data.rightLimit && safety > 0) { safety = safety -= 1; offset = data.currentOffset; var _range = createRangeAtCharacterOffset({ textNodes: textNodes, offset: data.currentOffset }); var _coords = _range.getBoundingClientRect(); distance = Math.abs(_coords.left - positionX); // up / down axis if (requiredOnFirstLine && hostCoords.top !== _coords.top) { moveLeft(data); continue; } else if (requiredOnLastLine && hostCoords.bottom !== _coords.bottom) { moveRight(data); continue; } // left / right axis if (positionX < _coords.left) { moveLeft(data); } else { moveRight(data); } } var range = createRangeAtCharacterOffset({ textNodes: textNodes, offset: data.currentOffset }); var coords = range.getBoundingClientRect(); var finalDistance = Math.abs(coords.left - positionX); // Decide if last or second last offset is closest if (finalDistance < distance) { distance = finalDistance; offset = data.currentOffset; } return { distance: distance, offset: offset, wasFound: true }; } // move the binary search index in between the current position and the left limit function moveLeft(data) { data.rightLimit = data.currentOffset; data.currentOffset = Math.floor((data.currentOffset + data.leftLimit) / 2); } // move the binary search index in between the current position and the right limit function moveRight(data) { data.leftLimit = data.currentOffset; data.currentOffset = Math.ceil((data.currentOffset + data.rightLimit) / 2); } function createRangeAtCharacterOffset(_ref2) { var textNodes = _ref2.textNodes, offset = _ref2.offset; var _getTextNodeAndRelati = (0, _element.getTextNodeAndRelativeOffset)({ textNodes: textNodes, absOffset: offset }), node = _getTextNodeAndRelati.node, relativeOffset = _getTextNodeAndRelati.relativeOffset; var newRange = node.ownerDocument.createRange(); newRange.setStart(node, relativeOffset); newRange.collapse(true); return newRange; }