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 runtime, odf, Node*/
 26 
 27 /**
 28  * Helper functions to retrieve information about an ODF document using a step iterator
 29  * @constructor
 30  */
 31 odf.StepUtils = function StepUtils() {
 32     "use strict";
 33 
 34     /**
 35      * Fetch the content bounds related to the step iterator's current position. This will return the text element, or
 36      * the content element immediately to the left of the step. Will return undefined if there is no content to the left
 37      * of the step.
 38      *
 39      * @param {!core.StepIterator} stepIterator
 40      * @return {!{container: !Node, startOffset: !number, endOffset: !number}|undefined}
 41      */
 42     function getContentBounds(stepIterator) {
 43         var container = stepIterator.container(),
 44             offset,
 45             contentBounds;
 46 
 47         runtime.assert(stepIterator.isStep(), "Step iterator must be on a step");
 48         // A step is to the left of the corresponding text content according to the TextPositionFilter.
 49         if (container.nodeType === Node.TEXT_NODE && stepIterator.offset() > 0) {
 50             offset = stepIterator.offset();
 51         } else {
 52             // If the container is not a text node, the content is expected to be found in the node to the left of the
 53             // current position.
 54             container = stepIterator.leftNode();
 55             if (container && container.nodeType === Node.TEXT_NODE) {
 56                 offset = /**@type{!Text}*/(container).length;
 57             }
 58         }
 59 
 60         if (container) {
 61             if (container.nodeType === Node.TEXT_NODE) {
 62                 // Based on the above logic, if the text offset is 0, the container to the left should have been
 63                 // used instead.
 64                 runtime.assert(offset > 0, "Empty text node found");
 65                 contentBounds = {
 66                     container: container,
 67                     startOffset: /**@type{!number}*/(offset) - 1,
 68                     endOffset: /**@type{!number}*/(offset)
 69                 };
 70             } else {
 71                 contentBounds = {
 72                     container: container,
 73                     startOffset: 0,
 74                     endOffset: container.childNodes.length
 75                 };
 76             }
 77         }
 78 
 79         return contentBounds;
 80     }
 81     this.getContentBounds = getContentBounds;
 82 };
 83