+
+var Cursor = function(canvas) {
+ this.canvas = canvas;
+};
+
+$.extend(Cursor.prototype, {
+ isSelecting: function() {
+ var selection = window.getSelection();
+ return !selection.isCollapsed;
+ },
+ isSelectingWithinElement: function() {
+ return this.isSelecting() && this.getSelectionStart().element.sameNode(this.getSelectionEnd().element);
+ },
+ isSelectingSiblings: function() {
+ return this.isSelecting() && this.getSelectionStart().element.parent().sameNode(this.getSelectionEnd().element.parent());
+ },
+ getPosition: function() {
+ return this.getSelectionAnchor();
+ },
+ getSelectionStart: function() {
+ return this.getSelectionBoundry('start');
+ },
+ getSelectionEnd: function() {
+ return this.getSelectionBoundry('end');
+ },
+ getSelectionAnchor: function() {
+ return this.getSelectionBoundry('anchor');
+ },
+ getSelectionFocus: function() {
+ return this.getSelectionBoundry('focus');
+ },
+ getSelectionBoundry: function(which) {
+ var selection = window.getSelection(),
+ anchorElement = this.canvas.getDocumentElement(selection.anchorNode),
+ focusElement = this.canvas.getDocumentElement(selection.focusNode);
+
+ var getOffset = function(where) {
+ var toret, node;
+ if(where === 'anchor') {
+ node = selection.anchorNode;
+ toret = selection.anchorOffset;
+ } else {
+ node = selection.focusNode;
+ toret = selection.focusOffset;
+ }
+
+ if(toret === 1 && node.data.charAt(0) === utils.unicode.ZWS)
+ toret = 0;
+ else if((toret === node.data.length - 1) && (node.data.charAt(node.data.length - 1) === utils.unicode.ZWS))
+ toret++;
+ return toret;
+ }
+
+ if((!anchorElement) || (anchorElement instanceof documentElement.DocumentNodeElement) || (!focusElement) || focusElement instanceof documentElement.DocumentNodeElement)
+ return {};
+
+ if(which === 'anchor') {
+ return {
+ element: anchorElement,
+ offset: getOffset('anchor'),
+ offsetAtBeginning: getOffset('anchor') === 0,
+ offsetAtEnd: selection.anchorNode.data.length === getOffset('anchor')
+ };
+ }
+ if(which === 'focus') {
+ return {
+ element: focusElement,
+ offset: getOffset('focus'),
+ offsetAtBeginning: getOffset('focus') === 0,
+ offsetAtEnd: selection.focusNode.data.length === getOffset('focus')
+ };
+ }
+
+ var element,
+ offset;
+
+ if(anchorElement.parent().sameNode(focusElement.parent())) {
+ var parent = anchorElement.parent(),
+ anchorFirst = parent.childIndex(anchorElement) < parent.childIndex(focusElement);
+ if(anchorFirst) {
+ if(which === 'start') {
+ element = anchorElement;
+ offset = getOffset('anchor')
+ }
+ else if(which === 'end') {
+ element = focusElement,
+ offset = getOffset('focus')
+ }
+ } else {
+ if(which === 'start') {
+ element = focusElement,
+ offset = getOffset('focus')
+ }
+ else if(which === 'end') {
+ element = anchorElement;
+ offset = getOffset('anchor')
+ }
+ }
+ } else {
+ // TODO: Handle order via https://developer.mozilla.org/en-US/docs/Web/API/Node.compareDocumentPosition
+ if(which === 'start') {
+ element = anchorElement;
+ offset = getOffset('anchor')
+ } else {
+ element = focusElement;
+ offset = getOffset('focus')
+ }
+ }
+
+ var nodeLen = (element.sameNode(focusElement) ? selection.focusNode : selection.anchorNode).length;
+ return {
+ element: element,
+ offset: offset,
+ offsetAtBeginning: offset === 0,
+ offsetAtEnd: nodeLen === offset
+ }
+ }
+})
+