1 /**
  2  * Copyright (C) 2010-2014 KO GmbH <copyright@kogmbh.com>
  3  *
  4  * @licstart
  5  * This file is part of WebODF.
  6  *
  7  * WebODF is free software: you can redistribute it and/or modify it
  8  * under the terms of the GNU Affero General Public License (GNU AGPL)
  9  * as published by the Free Software Foundation, either version 3 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * WebODF is distributed in the hope that it will be useful, but
 13  * WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU Affero General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Affero General Public License
 18  * along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 19  * @licend
 20  *
 21  * @source: http://www.webodf.org/
 22  * @source: https://github.com/kogmbh/WebODF/
 23  */
 24 
 25 /*global core, gui*/
 26 
 27 /**
 28  * Finds the closest step to the specified offset, but comparing the left and right edges of the
 29  * surrounding rectangles to the desired offset. Iteration will continue until the steps
 30  * start getting further away from the current closest step.
 31  *
 32  * @constructor
 33  * @implements {gui.VisualStepScanner}
 34  * @param {!number} offset Target horizontal offset
 35  */
 36 gui.ClosestXOffsetScanner = function (offset) {
 37     "use strict";
 38     var self = this,
 39         closestDiff,
 40         LEFT_TO_RIGHT = gui.StepInfo.VisualDirection.LEFT_TO_RIGHT;
 41 
 42     this.token = undefined;
 43 
 44     /**
 45      * Returns true if the supplied edgeOffset is further away from the desired offset
 46      * than one previously seen.
 47      *
 48      * @param {?number} edgeOffset
 49      * @return {!boolean}
 50      */
 51     function isFurtherFromOffset(edgeOffset) {
 52         if (edgeOffset !== null && closestDiff !== undefined) {
 53             return Math.abs(edgeOffset - offset) > closestDiff;
 54         }
 55         return false;
 56     }
 57 
 58     /**
 59      * Update the closestDiff if the supplied edge is closer to the offset
 60      * @param {?number} edge
 61      * @return {undefined}
 62      */
 63     function updateDiffIfSmaller(edge) {
 64         if (edge !== null && isFurtherFromOffset(edge) === false) {
 65             closestDiff = Math.abs(edge - offset);
 66         }
 67     }
 68 
 69     /**
 70      * @param {!gui.StepInfo} stepInfo
 71      * @param {?ClientRect} previousRect
 72      * @param {?ClientRect} nextRect
 73      * @return {!boolean}
 74      */
 75     this.process = function(stepInfo, previousRect, nextRect) {
 76         var edge1,
 77             edge2;
 78 
 79         // The cursor is always between the two rects.
 80         if (stepInfo.visualDirection === LEFT_TO_RIGHT) {
 81             // In an LTR visual direction, the caret is to the right of the previous rect
 82             edge1 = previousRect && previousRect.right;
 83             // and the left of the next rect
 84             edge2 = nextRect && nextRect.left;
 85         } else {
 86             // In an RTL visual direction, the caret is to the LEFT of the previous rect
 87             edge1 = previousRect && previousRect.left;
 88             // and the RIGHT of the next rect
 89             edge2 = nextRect && nextRect.right;
 90         }
 91 
 92         if (isFurtherFromOffset(edge1) || isFurtherFromOffset(edge2)) {
 93             // The current step is further away than the previous one, so terminate iteration
 94             return true;
 95         }
 96         if (previousRect || nextRect) {
 97             // At least one rectangle is visible, and is therefore a closer step than the last seen one
 98             updateDiffIfSmaller(edge1);
 99             updateDiffIfSmaller(edge2);
100             self.token = stepInfo.token;
101         }
102         return false;
103     };
104 };