Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: chrome/browser/resources/access_chromevox/chromevis/injected/lens.js

Issue 6254007: Adding ChromeVox as a component extensions (enabled only for ChromeOS, for no... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 /**
6 * @fileoverview Creates a CSS lens for displaying magnified text.
7 */
8
9 goog.provide('chromevis.ChromeVisLens');
10
11 goog.require('cvox.BuildConfig');
12 goog.require('cvox.ExtensionBridge');
13 goog.require('cvox.SelectionUtil');
14
15 /**
16 * Constructor for CSS lens. Initializes the lens settings.
17 * @constructor
18 */
19 chromevis.ChromeVisLens = function() {
20
21 /**
22 * The current amount of padding (in pixels) between the text
23 * and the sides of the lens
24 * @type {number}
25 * @private
26 */
27 this.padding_ = 5;
28
29 /**
30 * The maximum width of the bubble lens (in pixels)
31 * @type {number}
32 * @private
33 */
34 this.maxBubbleWidth_ = 700;
35
36 /**
37 * The minimum width of the bubble lens (in pixels)
38 * @type {number}
39 * @private
40 */
41 this.minBubbleWidth_ = 25;
42
43 /**
44 * Whether or not the lens is currently displayed
45 * @type {boolean}
46 * @private
47 */
48 this.isLensDisplayed_ = false;
49
50 /**
51 * Whether or not the lens is currently centered
52 * @type {boolean}
53 */
54 this.isCentered = true;
55
56 /**
57 * The current magnification multiplier
58 * @type {number}
59 */
60 this.multiplier = 1.5;
61
62 /**
63 * The current text color
64 * @type {string}
65 */
66 this.textColor = '#FFFFFF';
67
68 /**
69 * The current lens background color
70 * @type {string}
71 */
72 this.bgColor = '#000000';
73
74 /**
75 * Whether the lens is currently anchored to the top of the page
76 * @type {boolean}
77 */
78 this.isAnchored = true;
79
80 /**
81 * The current ChromeVis lens object
82 * @type {Element}
83 */
84 this.lens = chromevis.ChromeVisLens.ACTIVE_DOC.createElement('span');
85
86 this.initializeLens_();
87 };
88
89
90 /**
91 * The name of the special div that contains settings specified by the
92 * background page
93 * @type {string}
94 * @const
95 */
96 chromevis.ChromeVisLens.EL_ID = 'chromeVisBackground2LensDiv';
97
98 /**
99 * The name of the attribute specifying whether the lens is centered
100 * @type {string}
101 * @const
102 */
103 chromevis.ChromeVisLens.CENTER_ATTRB = 'data-isCentered';
104
105 /**
106 * The name of the attribute specifying the lens magnification
107 * @type {string}
108 * @const
109 */
110 chromevis.ChromeVisLens.MULT_ATTRB = 'data-textMag';
111
112 /**
113 * The name of the attribute specifying the lens text color
114 * @type {string}
115 * @const
116 */
117 chromevis.ChromeVisLens.TXT_COLOR_ATTRB = 'data-textColor';
118
119 /**
120 * The name of the attribute specifying the lens background color
121 * @type {string}
122 * @const
123 */
124 chromevis.ChromeVisLens.BG_COLOR_ATTRB = 'data-bgColor';
125
126 /**
127 * The name of the attribute specifying whether the lens is anchored
128 * @type {string}
129 * @const
130 */
131 chromevis.ChromeVisLens.ANCHOR_ATTRB = 'data-isAnchored';
132
133 /**
134 * The active document
135 * @type {Document}
136 * @const
137 */
138 chromevis.ChromeVisLens.ACTIVE_DOC = window.document;
139
140
141 /**
142 * Initializes the ChromeVis lens with settings pulled from background page.
143 * @private
144 */
145 chromevis.ChromeVisLens.prototype.initializeLens_ = function() {
146 this.initializeLensCSS_();
147
148 this.lens.style.display = 'none';
149 chromevis.ChromeVisLens.ACTIVE_DOC.body.appendChild(this.lens);
150
151 this.setupMessageListener_();
152
153 this.updateAnchorLens();
154 };
155
156
157 /**
158 * Listens for an event fired from the extension that indicates the background
159 * page is requesting the lens to update. This event was dispatched to a known
160 * div in the shared DOM (chromeVisBackground2LensDiv) and the div has
161 * attributes known to the lens that contain lens setting information. The
162 * lens reads information from the div and then updates appropriately.
163 * @private
164 */
165 chromevis.ChromeVisLens.prototype.setupMessageListener_ = function() {
166 if (BUILD_TYPE != BUILD_TYPE_CHROME) {
167 return;
168 }
169 var self = this;
170 cvox.ExtensionBridge.addMessageListener(function(message, port) {
171 switch (message.data) {
172 case 'data-isAnchored':
173 self.setAnchoredLens(message.value);
174 self.isAnchored ? self.updateAnchorLens() : self.updateBubbleLens();
175 break;
176 case 'data-isCentered':
177 self.isCentered = message.value;
178 if (!self.isAnchored) {
179 self.updateBubbleLens();
180 }
181 break;
182 case 'data-textMag':
183 var multData = message.value;
184 if (multData != null) {
185 self.multiplier = parseFloat(multData);
186 self.setMagnification();
187 // Must update position of lens after text size has changed
188 self.isAnchored ? self.updateAnchorLens() : self.updateBubbleLens();
189 }
190 break;
191 case 'data-textColor':
192 var textColorData = message.value;
193 if (textColorData != null) {
194 self.textColor = textColorData;
195 self.setTextColor();
196 }
197 break;
198 case 'data-bgColor':
199 var bgColorData = message.value;
200 if (bgColorData != null) {
201 self.bgColor = bgColorData;
202 self.setBgColor();
203 }
204 break;
205 }
206 });
207 };
208
209
210 /**
211 * Displays or hides the lens.
212 * @param {boolean} show Whether or not the lens should be shown.
213 */
214 chromevis.ChromeVisLens.prototype.showLens = function(show) {
215 show ? this.lens.style.display = 'block' :
216 this.lens.style.display = 'none';
217
218 this.isLensDisplayed_ = show;
219
220 this.isLensDisplayed_ ? this.updateText() : document.body.style.marginTop = 0;
221 };
222
223
224 /**
225 * Initializes the lens CSS.
226 * @private
227 */
228 chromevis.ChromeVisLens.prototype.initializeLensCSS_ = function() {
229 this.lens.style.backgroundColor = this.bgColor;
230
231 // Style settings
232 this.lens.style.borderColor = '#000000';
233 this.lens.style.borderWidth = 'medium';
234 this.lens.style.borderStyle = 'groove';
235
236 this.lens.style.position = 'absolute';
237
238 // Note: there is no specified maximum value for the zIndex.
239 // Occasionally there will be a website that has an element with a zIndex
240 // higher than this one. The only fix is to manually go here and increase
241 // the zIndex.
242 this.lens.style.zIndex = 100000000000;
243
244 this.lens.style.minHeight = 5 + 'px';
245
246 this.lens.style.webkitBorderRadius = '7px';
247
248 // Class setting - this special class name means ChromeVis will
249 // not try to select text content inside the lens.
250 this.lens.className = cvox.TraverseUtil.SKIP_CLASS;
251 };
252
253
254 /**
255 * Sets whether the lens is anchored to the top of the page or whether it floats
256 * near the selected text.
257 * @param {boolean} anchored Whether or not the lens is anchored.
258 */
259 chromevis.ChromeVisLens.prototype.setAnchoredLens = function(anchored) {
260 this.isAnchored = anchored;
261 if ((this.isLensDisplayed_) && (!this.isAnchored)) {
262 document.body.style.marginTop = 0;
263 }
264 };
265
266
267 /**
268 * Refreshes the position of the anchor lens on the page. This is usually done
269 * in response to scrolling or a window resize.
270 */
271 chromevis.ChromeVisLens.prototype.updateAnchorLens = function() {
272 this.lens.style.top = window.scrollY + 'px';
273 this.lens.style.minWidth = (window.innerWidth - 50) + 'px';
274 this.lens.style.maxWidth = (window.innerWidth - 50) + 'px';
275
276 this.lens.style.left = 10 + 'px';
277 this.lens.style.right = 100 + 'px';
278
279 // Push rest of document down underneath anchor lens.
280 // Does not work with documents that have absolutely positioned
281 // elements - because absolutely positioned element margins
282 // never collapse with global margins.
283
284 var bod = document.body;
285 // need to add 10 to the computed style to take into account the margin
286 var str_ht = window.getComputedStyle(this.lens, null).height;
287 var ht = parseInt(str_ht.substr(0, str_ht.length - 2), 10) + 20;
288 bod.style.marginTop = ht + 'px';
289 };
290
291
292 /**
293 * Refreshes the position of the bubble lens on the page. This is done in
294 * response to the selection changing or the window resizing.
295 */
296 chromevis.ChromeVisLens.prototype.updateBubbleLens = function() {
297 var sel = window.getSelection();
298 var pos = cvox.SelectionUtil.findSelPosition(sel);
299
300 var top;
301 var left;
302 if (pos == null) {
303 top = 0;
304 left = 0;
305 }
306 top = pos[0];
307 left = pos[1];
308
309 this.lens.style.minWidth = 0;
310
311 // Calculate maximum lens width
312 var parent;
313 var maxw;
314 if (this.isCentered) {
315 // Want width with lens centered in the parent element
316 // So maxwidth is width of parent
317 parent = sel.getRangeAt(0).commonAncestorContainer;
318 while (!parent.offsetWidth) {
319 parent = parent.parentNode;
320 }
321 maxw = Math.min(this.maxBubbleWidth_, parent.offsetWidth);
322 } else {
323 // Align the left edge of the lens with the left edge of the selection
324 // So find maxwidth with left edge aligned
325 maxw = Math.min(this.maxBubbleWidth_,
326 ((document.body.clientWidth - left) - 16));
327 }
328
329 this.lens.style.maxWidth = maxw + 'px';
330 // Now calculate lens left position
331 // First check if actual width is larger than maxWidth
332 if (this.lens.firstChild.scrollWidth > maxw) {
333 var shiftLeft = this.lens.firstChild.scrollWidth - maxw;
334
335 this.lens.style.maxWidth = this.lens.firstChild.scrollWidth + 'px';
336 this.lens.style.left = (left - shiftLeft) + 'px';
337 } else {
338 if (this.isCentered) {
339 // Center the lens in the parent element
340 var pleft = 0;
341 var obj = parent;
342
343 if (obj.offsetParent) {
344 pleft = obj.offsetLeft;
345 obj = obj.offsetParent;
346 while (obj !== null) {
347 pleft += obj.offsetLeft;
348 obj = obj.offsetParent;
349 }
350 }
351
352 this.lens.style.left =
353 Math.ceil((pleft + (parent.offsetWidth / 2)) -
354 (this.lens.firstChild.scrollWidth / 2)) +
355 'px';
356 } else {
357 // Align the left edge of the lens with the left edge of the selection
358 this.lens.style.left = left + 'px';
359 }
360 }
361 this.lens.style.right = 'auto';
362
363 // Calculate lens height and top position
364 var str_ht = window.getComputedStyle(this.lens, null).height;
365 var ht = parseInt(str_ht.substr(0, str_ht.length - 2), 10) + 20;
366
367 var actualTop = top - ht;
368 if (actualTop < 0) {
369 this.lens.style.top = 5 + 'px';
370 } else {
371 this.lens.style.top = actualTop + 'px';
372 }
373 };
374
375
376 /**
377 * Update the text displayed inside the lens. This is done in response to the
378 * selection changing.
379 */
380 chromevis.ChromeVisLens.prototype.updateText = function() {
381 if (this.isLensDisplayed_) {
382 // Need to replace current lens node due to Webkit caching some
383 // display settings between lens changes.
384 chromevis.ChromeVisLens.ACTIVE_DOC = window.document;
385 chromevis.ChromeVisLens.ACTIVE_DOC.body.removeChild(this.lens);
386 this.lens = chromevis.ChromeVisLens.ACTIVE_DOC.createElement('span');
387
388 this.initializeLensCSS_();
389
390 chromevis.ChromeVisLens.ACTIVE_DOC.body.appendChild(this.lens);
391
392 var sel = window.getSelection();
393 var selectedText = sel.toString();
394
395 if (selectedText == null) {
396 // No selection, but still need to update the lens so it
397 // has a consistent appearance
398 selectedText = '';
399 }
400
401 while (this.lens.firstChild) {
402 this.lens.removeChild(this.lens.firstChild);
403 }
404
405 var clonedNode = document.createElement('div');
406
407 // To preserve new lines in selected text, need to create child div nodes
408 // of the new element.
409 // This also guards against selected text that includes HTML tags.
410 var newSelectedText = '';
411 var childNode = document.createElement('div');
412
413 for (var i = 0; i < selectedText.length; i++) {
414 if ((selectedText.charCodeAt(i) == 10)) {
415 childNode.textContent = newSelectedText;
416 clonedNode.appendChild(childNode);
417 childNode = document.createElement('div');
418 newSelectedText = '';
419 } else {
420 newSelectedText = newSelectedText + selectedText.charAt(i);
421 }
422 }
423 childNode.textContent = newSelectedText;
424 clonedNode.appendChild(childNode);
425
426 // Style settings
427 clonedNode.style.fontFamily = 'Verdana, Arial, Helvetica, sans-serif';
428 clonedNode.style.fontWeight = 'normal';
429 clonedNode.style.fontStyle = 'normal';
430 clonedNode.style.color = this.textColor;
431 clonedNode.style.textDecoration = 'none';
432 clonedNode.style.textAlign = 'left';
433 clonedNode.style.lineHeight = 1.2;
434
435 this.lens.appendChild(clonedNode);
436
437 this.magnifyText_();
438 this.padText_();
439 this.isAnchored ? this.updateAnchorLens() : this.updateBubbleLens();
440 }
441 };
442
443
444 /**
445 * Updates the lens in response to a window resize.
446 */
447 chromevis.ChromeVisLens.prototype.updateResized = function() {
448 this.isAnchored ? this.updateAnchorLens() : this.updateBubbleLens();
449 };
450
451
452 /**
453 * Updates the lens in response to the document being scrolled;
454 */
455 chromevis.ChromeVisLens.prototype.updateScrolled = function() {
456 if (this.isAnchored) {
457 this.updateAnchorLens();
458
459 if (this.isLensDisplayed_) {
460 // Force redraw to counteract scroll acceleration problem
461 // Workaround: hide lens, check offsetHeight, display lens
462 // this forces a redraw
463 // TODO: file Chrome bug, get rid of this
464 this.lens.style.display = 'none';
465 var redrawFix = this.lens.offsetHeight;
466 this.lens.style.display = 'block';
467 }
468 }
469 };
470
471
472 /**
473 * Adjusts the text magnification.
474 * @private
475 */
476 chromevis.ChromeVisLens.prototype.magnifyText_ = function() {
477 var adjustment = (this.multiplier * 100) + '%';
478
479 if (this.lens.firstChild) {
480 if (this.lens.firstChild.hasChildNodes()) {
481 var children = this.lens.firstChild.childNodes;
482
483 for (var i = 0; i < children.length; i++) {
484 children[i].style.fontSize = adjustment;
485 }
486 }
487 }
488 };
489
490
491 /**
492 * Adjusts the padding around the text inside the lens.
493 * @private
494 */
495 chromevis.ChromeVisLens.prototype.padText_ = function() {
496 if (this.padding_ < 0) {
497 return;
498 }
499 this.lens.style.padding_ = this.padding_ + 'px';
500 };
501
502
503 /**
504 * Sets the text magnification multiplier.
505 */
506 chromevis.ChromeVisLens.prototype.setMagnification = function() {
507 this.magnifyText_();
508 this.padText_();
509 };
510
511
512 /**
513 * Returns the current text size multiplier for magnification.
514 * @return {number} The current text size multiplier.
515 */
516 chromevis.ChromeVisLens.prototype.getMagnification = function() {
517 return this.multiplier;
518 };
519
520
521 /**
522 * Returns the current background color.
523 * @return {string} The lens background color.
524 */
525 chromevis.ChromeVisLens.prototype.getBgColor = function() {
526 return this.bgColor;
527 };
528
529
530 /**
531 * Updates the lens background color.
532 */
533 chromevis.ChromeVisLens.prototype.setBgColor = function() {
534 this.lens.style.backgroundColor = this.bgColor;
535 };
536
537
538 /**
539 * Returns the current text color.
540 * @return {string} The lens text color.
541 */
542 chromevis.ChromeVisLens.prototype.getTextColor = function() {
543 return this.textColor;
544 };
545
546
547 /**
548 * Updates the lens text color.
549 */
550 chromevis.ChromeVisLens.prototype.setTextColor = function() {
551 if (this.lens.firstChild) {
552 this.lens.firstChild.style.color = this.textColor;
553 }
554 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698