Fixing handling zero width space on selection
authorAleksander Łukasz <aleksander.lukasz@nowoczesnapolska.org.pl>
Mon, 5 Aug 2013 12:45:50 +0000 (14:45 +0200)
committerAleksander Łukasz <aleksander.lukasz@nowoczesnapolska.org.pl>
Mon, 5 Aug 2013 12:45:50 +0000 (14:45 +0200)
modules/documentCanvas/canvas/canvas.js
modules/documentCanvas/canvas/canvas.test3.js

index 5f78277..cb9fb69 100644 (file)
@@ -584,23 +584,40 @@ $.extend(Cursor.prototype, {
             anchorElement = this.canvas.getDocumentElement(selection.anchorNode),
             focusElement = this.canvas.getDocumentElement(selection.focusNode);
         
-        if(anchorElement instanceof documentElement.DocumentNodeElement || focusElement instanceof documentElement.DocumentNodeElement)
+        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: selection.anchorOffset,
-                offsetAtBeginning: selection.anchorOffset === 0,
-                offsetAtEnd: anchorElement && anchorElement.getText().length === selection.anchorOffset
+                offset: getOffset('anchor'),
+                offsetAtBeginning: getOffset('anchor') === 0,
+                offsetAtEnd: selection.anchorNode.data.length === getOffset('anchor')
             };
         }
         if(which === 'focus') {
             return {
                 element: focusElement,
-                offset: selection.focusOffset,
-                offsetAtBeginning: selection.focusOffset === 0,
-                offsetAtEnd: focusElement && focusElement.getText().length === selection.focusOffset
+                offset: getOffset('focus'),
+                offsetAtBeginning: getOffset('focus') === 0,
+                offsetAtEnd: selection.focusElement.data.length === getOffset('focus')
             };
         }
         
@@ -613,38 +630,39 @@ $.extend(Cursor.prototype, {
             if(anchorFirst) {
                 if(which === 'start') {
                     element = anchorElement;
-                    offset = selection.anchorOffset;
+                    offset = getOffset('anchor')
                 }
                 else if(which === 'end') {
                     element = focusElement,
-                    offset = selection.focusOffset;
+                    offset = getOffset('focus')
                 }
             } else {
                 if(which === 'start') {
                     element = focusElement,
-                    offset = selection.focusOffset
+                    offset = getOffset('focus')
                 }
                 else if(which === 'end') {
                     element = anchorElement;
-                    offset = selection.anchorOffset;
+                    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 = selection.anchorOffset
+                offset = getOffset('anchor')
             } else {
                 element = focusElement;
-                offset = selection.focusOffset
+                offset = getOffset('focus')
             }
         }
 
+        var nodeLen = (element.sameNode(focusElement) ? selection.focusNode : selection.anchorNode).length;
         return {
             element: element,
             offset: offset,
             offsetAtBeginning: offset === 0,
-            offsetAtEnd: element.getText().length === offset
+            offsetAtEnd: nodeLen === offset
         }
     }
 })
index fc390ec..3c53f09 100644 (file)
@@ -2,8 +2,9 @@ define([
 'libs/chai',
 'libs/sinon',
 'modules/documentCanvas/canvas/canvas',
-'modules/documentCanvas/canvas/documentElement'
-], function(chai, sinon, canvas, documentElement) {
+'modules/documentCanvas/canvas/documentElement',
+'modules/documentCanvas/canvas/utils'
+], function(chai, sinon, canvas, documentElement, utils) {
     
 'use strict';
 
@@ -1111,6 +1112,25 @@ describe('Canvas', function() {
             expect(cursor.isSelectingSiblings()).to.equal(false, '"has" and "big" are not children');
             
         })
+
+        describe('zero width space handling', function() {
+            it('position range includes ZWS at the boundries of text in case when native selection api doesn\'t', function() {
+                var c = canvas.fromXML("<section>Alice</section>"),
+                    dom = c.doc().dom(),
+                    textNode = findTextNode(dom, 'Alice'),
+                    cursor = c.getCursor();
+
+                textNode.data = utils.unicode.ZWS + 'Alice';
+                getSelection.returns({anchorNode: textNode, anchorOffset: 1, focusNode: textNode, focusOffset: 1});
+                expect(cursor.getPosition().offset).to.equal(0);
+                expect(cursor.getPosition().offsetAtBeginning).to.equal(true, 'offset at beginning');
+                
+                textNode.data = 'Alice' + utils.unicode.ZWS;
+                getSelection.returns({anchorNode: textNode, anchorOffset: 5, focusNode: textNode, focusOffset: 5});
+                expect(cursor.getPosition().offset).to.equal(6);
+                expect(cursor.getPosition().offsetAtEnd).to.equal(true, 'offset at end');
+            });
+        });
     });
 
     describe('Serializing document to WLXML', function() {