diff options
Diffstat (limited to 'alarm/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js')
-rw-r--r-- | alarm/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/alarm/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js b/alarm/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js new file mode 100644 index 0000000..93f31b4 --- /dev/null +++ b/alarm/node_modules/jsdom/lib/jsdom/living/selection/Selection-impl.js @@ -0,0 +1,342 @@ +"use strict"; + +const DOMException = require("domexception/webidl2js-wrapper"); + +const NODE_TYPE = require("../node-type"); +const { nodeLength, nodeRoot } = require("../helpers/node"); +const { domSymbolTree } = require("../helpers/internal-constants"); +const { compareBoundaryPointsPosition } = require("../range/boundary-point"); + +const { setBoundaryPointStart, setBoundaryPointEnd } = require("../range/Range-impl"); + +const Range = require("../generated/Range"); +const { implForWrapper } = require("../generated/utils"); + +// https://w3c.github.io/selection-api/#dfn-direction +const SELECTION_DIRECTION = { + FORWARDS: 1, + BACKWARDS: -1, + DIRECTIONLESS: 0 +}; + +// https://w3c.github.io/selection-api/#dom-selection +class SelectionImpl { + constructor(globalObject) { + this._range = null; + this._direction = SELECTION_DIRECTION.DIRECTIONLESS; + + this._globalObject = globalObject; + } + + // https://w3c.github.io/selection-api/#dom-selection-anchornode + get anchorNode() { + const anchor = this._anchor; + return anchor ? anchor.node : null; + } + + // https://w3c.github.io/selection-api/#dom-selection-anchoroffset + get anchorOffset() { + const anchor = this._anchor; + return anchor ? anchor.offset : 0; + } + + // https://w3c.github.io/selection-api/#dom-selection-focusnode + get focusNode() { + const focus = this._focus; + return focus ? focus.node : null; + } + + // https://w3c.github.io/selection-api/#dom-selection-focusoffset + get focusOffset() { + const focus = this._focus; + return focus ? focus.offset : 0; + } + + // https://w3c.github.io/selection-api/#dom-selection-iscollapsed + get isCollapsed() { + return this._range === null || this._range.collapsed; + } + + // https://w3c.github.io/selection-api/#dom-selection-rangecount + get rangeCount() { + return this._isEmpty() ? 0 : 1; + } + + // https://w3c.github.io/selection-api/#dom-selection-type + get type() { + if (this._isEmpty()) { + return "None"; + } else if (this._range.collapsed) { + return "Caret"; + } + + return "Range"; + } + + // https://w3c.github.io/selection-api/#dom-selection-getrangeat + getRangeAt(index) { + if (index !== 0 || this._isEmpty()) { + throw DOMException.create(this._globalObject, ["Invalid range index.", "IndexSizeError"]); + } + + return this._range; + } + + // https://w3c.github.io/selection-api/#dom-selection-addrange + addRange(range) { + if (range._root === implForWrapper(this._globalObject._document) && this.rangeCount === 0) { + this._associateRange(range); + } + } + + // https://w3c.github.io/selection-api/#dom-selection-removerange + removeRange(range) { + if (range !== this._range) { + throw DOMException.create(this._globalObject, ["Invalid range.", "NotFoundError"]); + } + + this._associateRange(null); + } + + // https://w3c.github.io/selection-api/#dom-selection-removeallranges + removeAllRanges() { + this._associateRange(null); + } + + // https://w3c.github.io/selection-api/#dom-selection-empty + empty() { + this.removeAllRanges(); + } + + // https://w3c.github.io/selection-api/#dom-selection-collapse + collapse(node, offset) { + if (node === null) { + this.removeAllRanges(); + return; + } + + if (node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) { + throw DOMException.create(this._globalObject, [ + "DocumentType Node can't be used as boundary point.", + "InvalidNodeTypeError" + ]); + } + + if (offset > nodeLength(node)) { + throw DOMException.create(this._globalObject, ["Invalid range index.", "IndexSizeError"]); + } + + if (nodeRoot(node) !== implForWrapper(this._globalObject._document)) { + return; + } + + const newRange = Range.createImpl(this._globalObject, [], { + start: { node, offset: 0 }, + end: { node, offset: 0 } + }); + + setBoundaryPointStart(newRange, node, offset); + setBoundaryPointEnd(newRange, node, offset); + + this._associateRange(newRange); + } + + // https://w3c.github.io/selection-api/#dom-selection-setposition + setPosition(node, offset) { + this.collapse(node, offset); + } + + // https://w3c.github.io/selection-api/#dom-selection-collapsetostart + collapseToStart() { + if (this._isEmpty()) { + throw DOMException.create(this._globalObject, ["There is no selection to collapse.", "InvalidStateError"]); + } + + const { node, offset } = this._range._start; + const newRange = Range.createImpl(this._globalObject, [], { + start: { node, offset }, + end: { node, offset } + }); + + this._associateRange(newRange); + } + + // https://w3c.github.io/selection-api/#dom-selection-collapsetoend + collapseToEnd() { + if (this._isEmpty()) { + throw DOMException.create(this._globalObject, ["There is no selection to collapse.", "InvalidStateError"]); + } + + const { node, offset } = this._range._end; + const newRange = Range.createImpl(this._globalObject, [], { + start: { node, offset }, + end: { node, offset } + }); + + this._associateRange(newRange); + } + + // https://w3c.github.io/selection-api/#dom-selection-extend + extend(node, offset) { + if (nodeRoot(node) !== implForWrapper(this._globalObject._document)) { + return; + } + + if (this._isEmpty()) { + throw DOMException.create(this._globalObject, ["There is no selection to extend.", "InvalidStateError"]); + } + + const { _anchor: oldAnchor } = this; + const newFocus = { node, offset }; + + const newRange = Range.createImpl(this._globalObject, [], { + start: { node, offset: 0 }, + end: { node, offset: 0 } + }); + + if (nodeRoot(node) !== this._range._root) { + setBoundaryPointStart(newRange, newFocus.node, newFocus.offset); + setBoundaryPointEnd(newRange, newFocus.node, newFocus.offset); + } else if (compareBoundaryPointsPosition(oldAnchor, newFocus) <= 0) { + setBoundaryPointStart(newRange, oldAnchor.node, oldAnchor.offset); + setBoundaryPointEnd(newRange, newFocus.node, newFocus.offset); + } else { + setBoundaryPointStart(newRange, newFocus.node, newFocus.offset); + setBoundaryPointEnd(newRange, oldAnchor.node, oldAnchor.offset); + } + + this._associateRange(newRange); + + this._direction = compareBoundaryPointsPosition(newFocus, oldAnchor) === -1 ? + SELECTION_DIRECTION.BACKWARDS : + SELECTION_DIRECTION.FORWARDS; + } + + // https://w3c.github.io/selection-api/#dom-selection-setbaseandextent + setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset) { + if (anchorOffset > nodeLength(anchorNode) || focusOffset > nodeLength(focusNode)) { + throw DOMException.create(this._globalObject, ["Invalid anchor or focus offset.", "IndexSizeError"]); + } + + const document = implForWrapper(this._globalObject._document); + if (document !== nodeRoot(anchorNode) || document !== nodeRoot(focusNode)) { + return; + } + + const anchor = { node: anchorNode, offset: anchorOffset }; + const focus = { node: focusNode, offset: focusOffset }; + + let newRange; + if (compareBoundaryPointsPosition(anchor, focus) === -1) { + newRange = Range.createImpl(this._globalObject, [], { + start: { node: anchor.node, offset: anchor.offset }, + end: { node: focus.node, offset: focus.offset } + }); + } else { + newRange = Range.createImpl(this._globalObject, [], { + start: { node: focus.node, offset: focus.offset }, + end: { node: anchor.node, offset: anchor.offset } + }); + } + + this._associateRange(newRange); + + this._direction = compareBoundaryPointsPosition(focus, anchor) === -1 ? + SELECTION_DIRECTION.BACKWARDS : + SELECTION_DIRECTION.FORWARDS; + } + + // https://w3c.github.io/selection-api/#dom-selection-selectallchildren + selectAllChildren(node) { + if (node.nodeType === NODE_TYPE.DOCUMENT_TYPE_NODE) { + throw DOMException.create(this._globalObject, [ + "DocumentType Node can't be used as boundary point.", + "InvalidNodeTypeError" + ]); + } + + const document = implForWrapper(this._globalObject._document); + if (document !== nodeRoot(node)) { + return; + } + + const length = domSymbolTree.childrenCount(node); + + const newRange = Range.createImpl(this._globalObject, [], { + start: { node, offset: 0 }, + end: { node, offset: 0 } + }); + + setBoundaryPointStart(newRange, node, 0); + setBoundaryPointEnd(newRange, node, length); + + this._associateRange(newRange); + } + + // https://w3c.github.io/selection-api/#dom-selection-deletefromdocument + deleteFromDocument() { + if (!this._isEmpty()) { + this._range.deleteContents(); + } + } + + // https://w3c.github.io/selection-api/#dom-selection-containsnode + containsNode(node, allowPartialContainment) { + if (this._isEmpty() || nodeRoot(node) !== implForWrapper(this._globalObject._document)) { + return false; + } + + const { _start, _end } = this._range; + + const startIsBeforeNode = compareBoundaryPointsPosition(_start, { node, offset: 0 }) === -1; + const endIsAfterNode = compareBoundaryPointsPosition(_end, { node, offset: nodeLength(node) }) === 1; + + return allowPartialContainment ? + startIsBeforeNode || endIsAfterNode : + startIsBeforeNode && endIsAfterNode; + } + + // https://w3c.github.io/selection-api/#dom-selection-stringifier + toString() { + return this._range ? this._range.toString() : ""; + } + + // https://w3c.github.io/selection-api/#dfn-empty + _isEmpty() { + return this._range === null; + } + + // https://w3c.github.io/selection-api/#dfn-anchor + get _anchor() { + if (!this._range) { + return null; + } + + return this._direction === SELECTION_DIRECTION.FORWARDS ? + this._range._start : + this._range._end; + } + + // https://w3c.github.io/selection-api/#dfn-focus + get _focus() { + if (!this._range) { + return null; + } + + return this._direction === SELECTION_DIRECTION.FORWARDS ? + this._range._end : + this._range._start; + } + + _associateRange(newRange) { + this._range = newRange; + this._direction = newRange === null ? SELECTION_DIRECTION.DIRECTIONLESS : SELECTION_DIRECTION.FORWARDS; + + // TODO: Emit "selectionchange" event. At this time, there is currently no test in WPT covering this. + // https://w3c.github.io/selection-api/#selectionchange-event + } +} + +module.exports = { + implementation: SelectionImpl +}; |