mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00

* Make eslint sort our imports * fix missing deps in eslint rule (dae) Caught on Linux due to the stricter sandboxing * Remove exports-last eslint rule (for now?) * Adjust browserslist settings - We use ResizeObserver which is not supported in browsers like KaiOS, Baidu or Android UC * Raise minimum iOS version 13.4 - It's the first version that supports ResizeObserver * Apply new eslint rules to sort imports
111 lines
2.8 KiB
TypeScript
111 lines
2.8 KiB
TypeScript
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
import { elementIsEmpty, nodeIsElement } from "../../lib/dom";
|
|
import { ascend } from "../../lib/node";
|
|
|
|
export interface ChildNodeRange {
|
|
parent: Node;
|
|
startIndex: number;
|
|
/* exclusive end */
|
|
endIndex: number;
|
|
}
|
|
|
|
/**
|
|
* Indices should be >= 0 and startIndex < endIndex
|
|
*/
|
|
function makeChildNodeRange(
|
|
node: Node,
|
|
startIndex: number,
|
|
endIndex = startIndex + 1,
|
|
): ChildNodeRange {
|
|
return {
|
|
parent: node,
|
|
startIndex,
|
|
endIndex,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Result does not indicate the node itself but a supposed new node that
|
|
* entirely surrounds the passed in node
|
|
*/
|
|
export function nodeToChildNodeRange(node: Node): ChildNodeRange {
|
|
const parent = ascend(node);
|
|
const index = Array.prototype.indexOf.call(parent.childNodes, node);
|
|
|
|
return makeChildNodeRange(parent, index);
|
|
}
|
|
|
|
function toDOMRange(childNodeRange: ChildNodeRange): Range {
|
|
const range = new Range();
|
|
range.setStart(childNodeRange.parent, childNodeRange.startIndex);
|
|
range.setEnd(childNodeRange.parent, childNodeRange.endIndex);
|
|
|
|
return range;
|
|
}
|
|
|
|
export function areSiblingChildNodeRanges(
|
|
before: ChildNodeRange,
|
|
after: ChildNodeRange,
|
|
): boolean {
|
|
if (before.parent !== after.parent || before.endIndex > after.startIndex) {
|
|
return false;
|
|
}
|
|
|
|
if (before.endIndex === after.startIndex) {
|
|
return true;
|
|
}
|
|
|
|
for (let index = before.endIndex; index < after.startIndex; index++) {
|
|
const node = before.parent.childNodes[index];
|
|
|
|
if (!nodeIsElement(node) || !elementIsEmpty(node)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
export function coversWholeParent(childNodeRange: ChildNodeRange): boolean {
|
|
return (
|
|
childNodeRange.startIndex === 0 &&
|
|
childNodeRange.endIndex === childNodeRange.parent.childNodes.length
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Precondition: must be sibling child node ranges
|
|
*/
|
|
export function mergeChildNodeRanges(
|
|
before: ChildNodeRange,
|
|
after: ChildNodeRange,
|
|
): ChildNodeRange {
|
|
return {
|
|
parent: before.parent,
|
|
startIndex: before.startIndex,
|
|
endIndex: after.endIndex,
|
|
};
|
|
}
|
|
|
|
export function surroundChildNodeRangeWithNode(
|
|
childNodeRange: ChildNodeRange,
|
|
node: Node,
|
|
): void {
|
|
const range = toDOMRange(childNodeRange);
|
|
|
|
if (range.collapsed) {
|
|
/**
|
|
* If the range is collapsed to a single element, move the range inside the element.
|
|
* This prevents putting the surround above the base element.
|
|
*/
|
|
const selected = range.commonAncestorContainer.childNodes[range.startOffset];
|
|
|
|
if (nodeIsElement(selected)) {
|
|
range.selectNode(selected);
|
|
}
|
|
}
|
|
|
|
range.surroundContents(node);
|
|
}
|