Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / chromevox / common / content_editable_extractor.js
blobce0d9415f0d71d17deea72a6387e59747a217f59
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6 * @fileoverview Defines the ContentEditableExtractor class.
7 */
9 goog.provide('cvox.ContentEditableExtractor');
11 goog.require('cvox.Cursor');
12 goog.require('cvox.TraverseUtil');
14 /**
15 * Extracts the text and line break information from a contenteditable region.
16 * @constructor
18 cvox.ContentEditableExtractor = function() {
19 /**
20 * The extracted, flattened, text.
21 * @type {string}
22 * @private
24 this.text_ = '';
26 /**
27 * The start cursor/selection index.
28 * @type {number}
29 * @private
31 this.start_ = 0;
33 /**
34 * The end cursor/selection index.
35 * @type {number}
36 * @private
38 this.end_ = 0;
40 /**
41 * Map from line index to a data structure containing the start
42 * and end index within the line.
43 * @type {Object<number, {startIndex: number, endIndex: number}>}
44 * @private
46 this.lines_ = {};
48 /**
49 * Map from 0-based character index to 0-based line index.
50 * @type {Array<number>}
51 * @private
53 this.characterToLineMap_ = [];
56 /**
57 * Update the metadata.
58 * @param {Element} element The DOM element that's contentEditable.
60 cvox.ContentEditableExtractor.prototype.update = function(element) {
61 /**
62 * Map from line index to a data structure containing the start
63 * and end index within the line.
64 * @type {Object<number, {startIndex: number, endIndex: number}>}
66 var lines = {0: {startIndex: 0, endIndex: 0}};
67 var startCursor = new cvox.Cursor(element, 0, '');
68 var endCursor = startCursor.clone();
69 var range = document.createRange();
70 var rect;
71 var lineIndex = 0;
72 var lastBottom = null;
73 var text = '';
74 var textSize = 0;
75 var selectionStartIndex = -1;
76 var selectionEndIndex = -1;
77 var sel = window.getSelection();
78 var selectionStart = new cvox.Cursor(sel.baseNode, sel.baseOffset, '');
79 var selectionEnd = new cvox.Cursor(sel.extentNode, sel.extentOffset, '');
80 var setStart = false;
81 var setEnd = false;
82 while (true) {
83 var entered = [];
84 var left = [];
85 var c = cvox.TraverseUtil.forwardsChar(endCursor, entered, left);
86 var done = false;
87 if (!c) {
88 done = true;
90 for (var i = 0; i < left.length && !done; i++) {
91 if (left[i] == element) {
92 done = true;
95 if (done) {
96 break;
99 range.setStart(startCursor.node, startCursor.index);
100 range.setEnd(endCursor.node, endCursor.index);
101 rect = range.getBoundingClientRect();
102 if (!rect || rect.width == 0 || rect.height == 0) {
103 continue;
106 if (lastBottom !== null &&
107 rect.bottom != lastBottom &&
108 textSize > 0 &&
109 text.substr(-1).match(/\S/) &&
110 c.match(/\S/)) {
111 text += '\n';
112 textSize++;
115 if (startCursor.node != endCursor.node && endCursor.index > 0) {
116 range.setStart(endCursor.node, endCursor.index - 1);
117 rect = range.getBoundingClientRect();
118 if (!rect || rect.width == 0 || rect.height == 0) {
119 continue;
123 if (!setStart &&
124 selectionStartIndex == -1 &&
125 endCursor.node == selectionStart.node &&
126 endCursor.index >= selectionStart.index) {
127 if (endCursor.index > selectionStart.index) {
128 selectionStartIndex = textSize;
129 } else {
130 setStart = true;
133 if (!setEnd &&
134 selectionEndIndex == -1 &&
135 endCursor.node == selectionEnd.node &&
136 endCursor.index >= selectionEnd.index) {
137 if (endCursor.index > selectionEnd.index) {
138 selectionEndIndex = textSize;
139 } else {
140 setEnd = true;
144 if (lastBottom === null) {
145 // This is the first character we've successfully measured on this
146 // line. Save the vertical position but don't do anything else.
147 lastBottom = rect.bottom;
148 } else if (rect.bottom != lastBottom) {
149 lines[lineIndex].endIndex = textSize;
150 lineIndex++;
151 lines[lineIndex] = {startIndex: textSize, endIndex: textSize};
152 lastBottom = rect.bottom;
154 text += c;
155 textSize++;
156 startCursor = endCursor.clone();
158 if (setStart) {
159 selectionStartIndex = textSize;
160 setStart = false;
162 if (setEnd) {
163 selectionEndIndex = textSize;
164 setEnd = false;
168 // Finish up the last line.
169 lines[lineIndex].endIndex = textSize;
171 // Create a map from character index to line number.
172 var characterToLineMap = [];
173 for (var i = 0; i <= lineIndex; i++) {
174 for (var j = lines[i].startIndex; j <= lines[i].endIndex; j++) {
175 characterToLineMap[j] = i;
179 // Finish updating fields.
180 this.text_ = text;
181 this.characterToLineMap_ = characterToLineMap;
182 this.lines_ = lines;
184 this.start_ = selectionStartIndex >= 0 ? selectionStartIndex : text.length;
185 this.end_ = selectionEndIndex >= 0 ? selectionEndIndex : text.length;
189 * Get the text.
190 * @return {string} The extracted, flattened, text.
192 cvox.ContentEditableExtractor.prototype.getText = function() {
193 return this.text_;
197 * @return {number} The start cursor/selection index.
199 cvox.ContentEditableExtractor.prototype.getStartIndex = function() {
200 return this.start_;
204 * @return {number} The end cursor/selection index.
206 cvox.ContentEditableExtractor.prototype.getEndIndex = function() {
207 return this.end_;
211 * Get the line number corresponding to a particular index.
212 * @param {number} index The 0-based character index.
213 * @return {number} The 0-based line number corresponding to that character.
215 cvox.ContentEditableExtractor.prototype.getLineIndex = function(index) {
216 return this.characterToLineMap_[index];
220 * Get the start character index of a line.
221 * @param {number} index The 0-based line index.
222 * @return {number} The 0-based index of the first character in this line.
224 cvox.ContentEditableExtractor.prototype.getLineStart = function(index) {
225 return this.lines_[index].startIndex;
229 * Get the end character index of a line.
230 * @param {number} index The 0-based line index.
231 * @return {number} The 0-based index of the end of this line.
233 cvox.ContentEditableExtractor.prototype.getLineEnd = function(index) {
234 return this.lines_[index].endIndex;