all files / src/ ve.SelectionState.js

96.88% Statements 31/32
94.44% Branches 17/18
100% Functions 5/5
96.88% Lines 31/32
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127                                              4495× 4495× 4495× 4495×   4495× 4495×   1507×     4495× 4495×   3843×                                     853×                                                               3930×                           1033× 1033×   1028× 1028×   1021× 1021× 141×     1028×    
/*!
 * VisualEditor DOM selection-like class
 *
 * @copyright 2011-2019 VisualEditor Team and others; see http://ve.mit-license.org
 */
 
/**
 * Like the DOM Selection object, but not updated live from the actual selection
 *
 * WARNING: the Nodes are still live and mutable, which can change the meaning
 * of the offsets or invalidate the value of isBackwards.
 *
 * @class
 *
 * @constructor
 * @param {ve.SelectionState|Selection|Object} selection DOM Selection-like object
 * @param {Node|null} selection.anchorNode The anchor node (null if no selection)
 * @param {number} selection.anchorOffset The anchor offset (0 if no selection)
 * @param {Node|null} selection.focusNode The focus node (null if no selection)
 * @param {number} selection.focusOffset The focus offset (0 if no selection)
 * @param {boolean} [selection.isCollapsed] Whether the anchor and focus are the same
 * @param {boolean} [selection.isBackwards] Whether the focus is before the anchor in document order
 */
ve.SelectionState = function VeSelectionState( selection ) {
	this.anchorNode = selection.anchorNode;
	this.anchorOffset = selection.anchorOffset;
	this.focusNode = selection.focusNode;
	this.focusOffset = selection.focusOffset;
 
	this.isCollapsed = selection.isCollapsed;
	if ( this.isCollapsed === undefined ) {
		// Set to true if nodes are null (matches DOM Selection object's behaviour)
		this.isCollapsed = this.anchorNode === this.focusNode &&
			this.anchorOffset === this.focusOffset;
	}
	this.isBackwards = selection.isBackwards;
	if ( this.isBackwards === undefined ) {
		// Set to false if nodes are null or focus is no earlier than anchor
		this.isBackwards = ve.compareDocumentOrder(
			this.focusNode,
			this.focusOffset,
			this.anchorNode,
			this.anchorOffset
		) < 0;
	}
};
 
/* Inheritance */
 
OO.initClass( ve.SelectionState );
 
/* Static methods */
 
/**
 * Create a selection state object representing no selection
 *
 * @return {ve.SelectionState} Object representing no selection
 */
ve.SelectionState.static.newNullSelection = function () {
	return new ve.SelectionState( {
		focusNode: null,
		focusOffset: 0,
		anchorNode: null,
		anchorOffset: 0
	} );
};
 
/* Methods */
 
/**
 * Returns the selection with the anchor and focus swapped
 *
 * @return {ve.SelectionState} selection with anchor/focus swapped. Object-identical to this if isCollapsed
 */
ve.SelectionState.prototype.flip = function () {
	Iif ( this.isCollapsed ) {
		return this;
	}
	return new ve.SelectionState( {
		anchorNode: this.focusNode,
		anchorOffset: this.focusOffset,
		focusNode: this.anchorNode,
		focusOffset: this.anchorOffset,
		isCollapsed: false,
		isBackwards: !this.isBackwards
	} );
};
 
/**
 * Whether the selection represents is the same range as another DOM Selection-like object
 *
 * @param {Object} other DOM Selection-like object
 * @return {boolean} True if the anchors/focuses are equal (including null)
 */
ve.SelectionState.prototype.equalsSelection = function ( other ) {
	return this.anchorNode === other.anchorNode &&
		this.anchorOffset === other.anchorOffset &&
		this.focusNode === other.focusNode &&
		this.focusOffset === other.focusOffset;
};
 
/**
 * Get a range representation of the selection
 *
 * N.B. Range objects do not show whether the selection is backwards
 *
 * @param {HTMLDocument} doc The owner document of the selection nodes
 * @return {Range|null} Range
 */
ve.SelectionState.prototype.getNativeRange = function ( doc ) {
	var range;
	if ( this.anchorNode === null ) {
		return null;
	}
	range = doc.createRange();
	if ( this.isBackwards ) {
		range.setStart( this.focusNode, this.focusOffset );
		range.setEnd( this.anchorNode, this.anchorOffset );
	} else {
		range.setStart( this.anchorNode, this.anchorOffset );
		if ( !this.isCollapsed ) {
			range.setEnd( this.focusNode, this.focusOffset );
		}
	}
	return range;
};