Index: chrome/browser/resources/access_chromevox/chromevis/injected/lens.js |
=================================================================== |
--- chrome/browser/resources/access_chromevox/chromevis/injected/lens.js (revision 0) |
+++ chrome/browser/resources/access_chromevox/chromevis/injected/lens.js (revision 0) |
@@ -0,0 +1,554 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+/** |
+ * @fileoverview Creates a CSS lens for displaying magnified text. |
+ */ |
+ |
+goog.provide('chromevis.ChromeVisLens'); |
+ |
+goog.require('cvox.BuildConfig'); |
+goog.require('cvox.ExtensionBridge'); |
+goog.require('cvox.SelectionUtil'); |
+ |
+/** |
+ * Constructor for CSS lens. Initializes the lens settings. |
+ * @constructor |
+ */ |
+chromevis.ChromeVisLens = function() { |
+ |
+ /** |
+ * The current amount of padding (in pixels) between the text |
+ * and the sides of the lens |
+ * @type {number} |
+ * @private |
+ */ |
+ this.padding_ = 5; |
+ |
+ /** |
+ * The maximum width of the bubble lens (in pixels) |
+ * @type {number} |
+ * @private |
+ */ |
+ this.maxBubbleWidth_ = 700; |
+ |
+ /** |
+ * The minimum width of the bubble lens (in pixels) |
+ * @type {number} |
+ * @private |
+ */ |
+ this.minBubbleWidth_ = 25; |
+ |
+ /** |
+ * Whether or not the lens is currently displayed |
+ * @type {boolean} |
+ * @private |
+ */ |
+ this.isLensDisplayed_ = false; |
+ |
+ /** |
+ * Whether or not the lens is currently centered |
+ * @type {boolean} |
+ */ |
+ this.isCentered = true; |
+ |
+ /** |
+ * The current magnification multiplier |
+ * @type {number} |
+ */ |
+ this.multiplier = 1.5; |
+ |
+ /** |
+ * The current text color |
+ * @type {string} |
+ */ |
+ this.textColor = '#FFFFFF'; |
+ |
+ /** |
+ * The current lens background color |
+ * @type {string} |
+ */ |
+ this.bgColor = '#000000'; |
+ |
+ /** |
+ * Whether the lens is currently anchored to the top of the page |
+ * @type {boolean} |
+ */ |
+ this.isAnchored = true; |
+ |
+ /** |
+ * The current ChromeVis lens object |
+ * @type {Element} |
+ */ |
+ this.lens = chromevis.ChromeVisLens.ACTIVE_DOC.createElement('span'); |
+ |
+ this.initializeLens_(); |
+}; |
+ |
+ |
+/** |
+ * The name of the special div that contains settings specified by the |
+ * background page |
+ * @type {string} |
+ * @const |
+ */ |
+chromevis.ChromeVisLens.EL_ID = 'chromeVisBackground2LensDiv'; |
+ |
+/** |
+ * The name of the attribute specifying whether the lens is centered |
+ * @type {string} |
+ * @const |
+ */ |
+chromevis.ChromeVisLens.CENTER_ATTRB = 'data-isCentered'; |
+ |
+/** |
+ * The name of the attribute specifying the lens magnification |
+ * @type {string} |
+ * @const |
+ */ |
+chromevis.ChromeVisLens.MULT_ATTRB = 'data-textMag'; |
+ |
+/** |
+ * The name of the attribute specifying the lens text color |
+ * @type {string} |
+ * @const |
+ */ |
+chromevis.ChromeVisLens.TXT_COLOR_ATTRB = 'data-textColor'; |
+ |
+/** |
+ * The name of the attribute specifying the lens background color |
+ * @type {string} |
+ * @const |
+ */ |
+chromevis.ChromeVisLens.BG_COLOR_ATTRB = 'data-bgColor'; |
+ |
+/** |
+ * The name of the attribute specifying whether the lens is anchored |
+ * @type {string} |
+ * @const |
+ */ |
+chromevis.ChromeVisLens.ANCHOR_ATTRB = 'data-isAnchored'; |
+ |
+/** |
+ * The active document |
+ * @type {Document} |
+ * @const |
+ */ |
+chromevis.ChromeVisLens.ACTIVE_DOC = window.document; |
+ |
+ |
+/** |
+ * Initializes the ChromeVis lens with settings pulled from background page. |
+ * @private |
+ */ |
+chromevis.ChromeVisLens.prototype.initializeLens_ = function() { |
+ this.initializeLensCSS_(); |
+ |
+ this.lens.style.display = 'none'; |
+ chromevis.ChromeVisLens.ACTIVE_DOC.body.appendChild(this.lens); |
+ |
+ this.setupMessageListener_(); |
+ |
+ this.updateAnchorLens(); |
+}; |
+ |
+ |
+/** |
+ * Listens for an event fired from the extension that indicates the background |
+ * page is requesting the lens to update. This event was dispatched to a known |
+ * div in the shared DOM (chromeVisBackground2LensDiv) and the div has |
+ * attributes known to the lens that contain lens setting information. The |
+ * lens reads information from the div and then updates appropriately. |
+ * @private |
+ */ |
+chromevis.ChromeVisLens.prototype.setupMessageListener_ = function() { |
+ if (BUILD_TYPE != BUILD_TYPE_CHROME) { |
+ return; |
+ } |
+ var self = this; |
+ cvox.ExtensionBridge.addMessageListener(function(message, port) { |
+ switch (message.data) { |
+ case 'data-isAnchored': |
+ self.setAnchoredLens(message.value); |
+ self.isAnchored ? self.updateAnchorLens() : self.updateBubbleLens(); |
+ break; |
+ case 'data-isCentered': |
+ self.isCentered = message.value; |
+ if (!self.isAnchored) { |
+ self.updateBubbleLens(); |
+ } |
+ break; |
+ case 'data-textMag': |
+ var multData = message.value; |
+ if (multData != null) { |
+ self.multiplier = parseFloat(multData); |
+ self.setMagnification(); |
+ // Must update position of lens after text size has changed |
+ self.isAnchored ? self.updateAnchorLens() : self.updateBubbleLens(); |
+ } |
+ break; |
+ case 'data-textColor': |
+ var textColorData = message.value; |
+ if (textColorData != null) { |
+ self.textColor = textColorData; |
+ self.setTextColor(); |
+ } |
+ break; |
+ case 'data-bgColor': |
+ var bgColorData = message.value; |
+ if (bgColorData != null) { |
+ self.bgColor = bgColorData; |
+ self.setBgColor(); |
+ } |
+ break; |
+ } |
+ }); |
+}; |
+ |
+ |
+/** |
+ * Displays or hides the lens. |
+ * @param {boolean} show Whether or not the lens should be shown. |
+ */ |
+chromevis.ChromeVisLens.prototype.showLens = function(show) { |
+ show ? this.lens.style.display = 'block' : |
+ this.lens.style.display = 'none'; |
+ |
+ this.isLensDisplayed_ = show; |
+ |
+ this.isLensDisplayed_ ? this.updateText() : document.body.style.marginTop = 0; |
+}; |
+ |
+ |
+/** |
+ * Initializes the lens CSS. |
+ * @private |
+ */ |
+chromevis.ChromeVisLens.prototype.initializeLensCSS_ = function() { |
+ this.lens.style.backgroundColor = this.bgColor; |
+ |
+ // Style settings |
+ this.lens.style.borderColor = '#000000'; |
+ this.lens.style.borderWidth = 'medium'; |
+ this.lens.style.borderStyle = 'groove'; |
+ |
+ this.lens.style.position = 'absolute'; |
+ |
+ // Note: there is no specified maximum value for the zIndex. |
+ // Occasionally there will be a website that has an element with a zIndex |
+ // higher than this one. The only fix is to manually go here and increase |
+ // the zIndex. |
+ this.lens.style.zIndex = 100000000000; |
+ |
+ this.lens.style.minHeight = 5 + 'px'; |
+ |
+ this.lens.style.webkitBorderRadius = '7px'; |
+ |
+ // Class setting - this special class name means ChromeVis will |
+ // not try to select text content inside the lens. |
+ this.lens.className = cvox.TraverseUtil.SKIP_CLASS; |
+}; |
+ |
+ |
+/** |
+ * Sets whether the lens is anchored to the top of the page or whether it floats |
+ * near the selected text. |
+ * @param {boolean} anchored Whether or not the lens is anchored. |
+ */ |
+chromevis.ChromeVisLens.prototype.setAnchoredLens = function(anchored) { |
+ this.isAnchored = anchored; |
+ if ((this.isLensDisplayed_) && (!this.isAnchored)) { |
+ document.body.style.marginTop = 0; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Refreshes the position of the anchor lens on the page. This is usually done |
+ * in response to scrolling or a window resize. |
+ */ |
+chromevis.ChromeVisLens.prototype.updateAnchorLens = function() { |
+ this.lens.style.top = window.scrollY + 'px'; |
+ this.lens.style.minWidth = (window.innerWidth - 50) + 'px'; |
+ this.lens.style.maxWidth = (window.innerWidth - 50) + 'px'; |
+ |
+ this.lens.style.left = 10 + 'px'; |
+ this.lens.style.right = 100 + 'px'; |
+ |
+ // Push rest of document down underneath anchor lens. |
+ // Does not work with documents that have absolutely positioned |
+ // elements - because absolutely positioned element margins |
+ // never collapse with global margins. |
+ |
+ var bod = document.body; |
+ // need to add 10 to the computed style to take into account the margin |
+ var str_ht = window.getComputedStyle(this.lens, null).height; |
+ var ht = parseInt(str_ht.substr(0, str_ht.length - 2), 10) + 20; |
+ bod.style.marginTop = ht + 'px'; |
+}; |
+ |
+ |
+/** |
+ * Refreshes the position of the bubble lens on the page. This is done in |
+ * response to the selection changing or the window resizing. |
+ */ |
+chromevis.ChromeVisLens.prototype.updateBubbleLens = function() { |
+ var sel = window.getSelection(); |
+ var pos = cvox.SelectionUtil.findSelPosition(sel); |
+ |
+ var top; |
+ var left; |
+ if (pos == null) { |
+ top = 0; |
+ left = 0; |
+ } |
+ top = pos[0]; |
+ left = pos[1]; |
+ |
+ this.lens.style.minWidth = 0; |
+ |
+ // Calculate maximum lens width |
+ var parent; |
+ var maxw; |
+ if (this.isCentered) { |
+ // Want width with lens centered in the parent element |
+ // So maxwidth is width of parent |
+ parent = sel.getRangeAt(0).commonAncestorContainer; |
+ while (!parent.offsetWidth) { |
+ parent = parent.parentNode; |
+ } |
+ maxw = Math.min(this.maxBubbleWidth_, parent.offsetWidth); |
+ } else { |
+ // Align the left edge of the lens with the left edge of the selection |
+ // So find maxwidth with left edge aligned |
+ maxw = Math.min(this.maxBubbleWidth_, |
+ ((document.body.clientWidth - left) - 16)); |
+ } |
+ |
+ this.lens.style.maxWidth = maxw + 'px'; |
+ // Now calculate lens left position |
+ // First check if actual width is larger than maxWidth |
+ if (this.lens.firstChild.scrollWidth > maxw) { |
+ var shiftLeft = this.lens.firstChild.scrollWidth - maxw; |
+ |
+ this.lens.style.maxWidth = this.lens.firstChild.scrollWidth + 'px'; |
+ this.lens.style.left = (left - shiftLeft) + 'px'; |
+ } else { |
+ if (this.isCentered) { |
+ // Center the lens in the parent element |
+ var pleft = 0; |
+ var obj = parent; |
+ |
+ if (obj.offsetParent) { |
+ pleft = obj.offsetLeft; |
+ obj = obj.offsetParent; |
+ while (obj !== null) { |
+ pleft += obj.offsetLeft; |
+ obj = obj.offsetParent; |
+ } |
+ } |
+ |
+ this.lens.style.left = |
+ Math.ceil((pleft + (parent.offsetWidth / 2)) - |
+ (this.lens.firstChild.scrollWidth / 2)) + |
+ 'px'; |
+ } else { |
+ // Align the left edge of the lens with the left edge of the selection |
+ this.lens.style.left = left + 'px'; |
+ } |
+ } |
+ this.lens.style.right = 'auto'; |
+ |
+ // Calculate lens height and top position |
+ var str_ht = window.getComputedStyle(this.lens, null).height; |
+ var ht = parseInt(str_ht.substr(0, str_ht.length - 2), 10) + 20; |
+ |
+ var actualTop = top - ht; |
+ if (actualTop < 0) { |
+ this.lens.style.top = 5 + 'px'; |
+ } else { |
+ this.lens.style.top = actualTop + 'px'; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Update the text displayed inside the lens. This is done in response to the |
+ * selection changing. |
+ */ |
+chromevis.ChromeVisLens.prototype.updateText = function() { |
+ if (this.isLensDisplayed_) { |
+ // Need to replace current lens node due to Webkit caching some |
+ // display settings between lens changes. |
+ chromevis.ChromeVisLens.ACTIVE_DOC = window.document; |
+ chromevis.ChromeVisLens.ACTIVE_DOC.body.removeChild(this.lens); |
+ this.lens = chromevis.ChromeVisLens.ACTIVE_DOC.createElement('span'); |
+ |
+ this.initializeLensCSS_(); |
+ |
+ chromevis.ChromeVisLens.ACTIVE_DOC.body.appendChild(this.lens); |
+ |
+ var sel = window.getSelection(); |
+ var selectedText = sel.toString(); |
+ |
+ if (selectedText == null) { |
+ // No selection, but still need to update the lens so it |
+ // has a consistent appearance |
+ selectedText = ''; |
+ } |
+ |
+ while (this.lens.firstChild) { |
+ this.lens.removeChild(this.lens.firstChild); |
+ } |
+ |
+ var clonedNode = document.createElement('div'); |
+ |
+ // To preserve new lines in selected text, need to create child div nodes |
+ // of the new element. |
+ // This also guards against selected text that includes HTML tags. |
+ var newSelectedText = ''; |
+ var childNode = document.createElement('div'); |
+ |
+ for (var i = 0; i < selectedText.length; i++) { |
+ if ((selectedText.charCodeAt(i) == 10)) { |
+ childNode.textContent = newSelectedText; |
+ clonedNode.appendChild(childNode); |
+ childNode = document.createElement('div'); |
+ newSelectedText = ''; |
+ } else { |
+ newSelectedText = newSelectedText + selectedText.charAt(i); |
+ } |
+ } |
+ childNode.textContent = newSelectedText; |
+ clonedNode.appendChild(childNode); |
+ |
+ // Style settings |
+ clonedNode.style.fontFamily = 'Verdana, Arial, Helvetica, sans-serif'; |
+ clonedNode.style.fontWeight = 'normal'; |
+ clonedNode.style.fontStyle = 'normal'; |
+ clonedNode.style.color = this.textColor; |
+ clonedNode.style.textDecoration = 'none'; |
+ clonedNode.style.textAlign = 'left'; |
+ clonedNode.style.lineHeight = 1.2; |
+ |
+ this.lens.appendChild(clonedNode); |
+ |
+ this.magnifyText_(); |
+ this.padText_(); |
+ this.isAnchored ? this.updateAnchorLens() : this.updateBubbleLens(); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Updates the lens in response to a window resize. |
+ */ |
+chromevis.ChromeVisLens.prototype.updateResized = function() { |
+ this.isAnchored ? this.updateAnchorLens() : this.updateBubbleLens(); |
+}; |
+ |
+ |
+/** |
+ * Updates the lens in response to the document being scrolled; |
+ */ |
+chromevis.ChromeVisLens.prototype.updateScrolled = function() { |
+ if (this.isAnchored) { |
+ this.updateAnchorLens(); |
+ |
+ if (this.isLensDisplayed_) { |
+ // Force redraw to counteract scroll acceleration problem |
+ // Workaround: hide lens, check offsetHeight, display lens |
+ // this forces a redraw |
+ // TODO: file Chrome bug, get rid of this |
+ this.lens.style.display = 'none'; |
+ var redrawFix = this.lens.offsetHeight; |
+ this.lens.style.display = 'block'; |
+ } |
+ } |
+}; |
+ |
+ |
+/** |
+ * Adjusts the text magnification. |
+ * @private |
+ */ |
+chromevis.ChromeVisLens.prototype.magnifyText_ = function() { |
+ var adjustment = (this.multiplier * 100) + '%'; |
+ |
+ if (this.lens.firstChild) { |
+ if (this.lens.firstChild.hasChildNodes()) { |
+ var children = this.lens.firstChild.childNodes; |
+ |
+ for (var i = 0; i < children.length; i++) { |
+ children[i].style.fontSize = adjustment; |
+ } |
+ } |
+ } |
+}; |
+ |
+ |
+/** |
+ * Adjusts the padding around the text inside the lens. |
+ * @private |
+ */ |
+chromevis.ChromeVisLens.prototype.padText_ = function() { |
+ if (this.padding_ < 0) { |
+ return; |
+ } |
+ this.lens.style.padding_ = this.padding_ + 'px'; |
+}; |
+ |
+ |
+/** |
+ * Sets the text magnification multiplier. |
+ */ |
+chromevis.ChromeVisLens.prototype.setMagnification = function() { |
+ this.magnifyText_(); |
+ this.padText_(); |
+}; |
+ |
+ |
+/** |
+ * Returns the current text size multiplier for magnification. |
+ * @return {number} The current text size multiplier. |
+ */ |
+chromevis.ChromeVisLens.prototype.getMagnification = function() { |
+ return this.multiplier; |
+}; |
+ |
+ |
+/** |
+ * Returns the current background color. |
+ * @return {string} The lens background color. |
+ */ |
+chromevis.ChromeVisLens.prototype.getBgColor = function() { |
+ return this.bgColor; |
+}; |
+ |
+ |
+/** |
+ * Updates the lens background color. |
+ */ |
+chromevis.ChromeVisLens.prototype.setBgColor = function() { |
+ this.lens.style.backgroundColor = this.bgColor; |
+}; |
+ |
+ |
+/** |
+ * Returns the current text color. |
+ * @return {string} The lens text color. |
+ */ |
+chromevis.ChromeVisLens.prototype.getTextColor = function() { |
+ return this.textColor; |
+}; |
+ |
+ |
+/** |
+ * Updates the lens text color. |
+ */ |
+chromevis.ChromeVisLens.prototype.setTextColor = function() { |
+ if (this.lens.firstChild) { |
+ this.lens.firstChild.style.color = this.textColor; |
+ } |
+}; |
Property changes on: chrome/browser/resources/access_chromevox/chromevis/injected/lens.js |
___________________________________________________________________ |
Added: svn:executable |
+ * |
Added: svn:eol-style |
+ LF |