| Index: ui/accessibility/extensions/caretbrowsing/caretbrowsing.js
|
| diff --git a/ui/accessibility/extensions/caretbrowsing/caretbrowsing.js b/ui/accessibility/extensions/caretbrowsing/caretbrowsing.js
|
| deleted file mode 100644
|
| index 4e1e7bf1060c6a36dd3e7958ca7f164f5804165e..0000000000000000000000000000000000000000
|
| --- a/ui/accessibility/extensions/caretbrowsing/caretbrowsing.js
|
| +++ /dev/null
|
| @@ -1,1424 +0,0 @@
|
| -/* Copyright (c) 2014 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 Caret browsing content script, runs in each frame.
|
| - *
|
| - * The behavior is based on Mozilla's spec whenever possible:
|
| - * http://www.mozilla.org/access/keyboard/proposal
|
| - *
|
| - * The one exception is that Esc is used to escape out of a form control,
|
| - * rather than their proposed key (which doesn't seem to work in the
|
| - * latest Firefox anyway).
|
| - *
|
| - * Some details about how Chrome selection works, which will help in
|
| - * understanding the code:
|
| - *
|
| - * The Selection object (window.getSelection()) has four components that
|
| - * completely describe the state of the caret or selection:
|
| - *
|
| - * base and anchor: this is the start of the selection, the fixed point.
|
| - * extent and focus: this is the end of the selection, the part that
|
| - * moves when you hold down shift and press the left or right arrows.
|
| - *
|
| - * When the selection is a cursor, the base, anchor, extent, and focus are
|
| - * all the same.
|
| - *
|
| - * There's only one time when the base and anchor are not the same, or the
|
| - * extent and focus are not the same, and that's when the selection is in
|
| - * an ambiguous state - i.e. it's not clear which edge is the focus and which
|
| - * is the anchor. As an example, if you double-click to select a word, then
|
| - * the behavior is dependent on your next action. If you press Shift+Right,
|
| - * the right edge becomes the focus. But if you press Shift+Left, the left
|
| - * edge becomes the focus.
|
| - *
|
| - * When the selection is in an ambiguous state, the base and extent are set
|
| - * to the position where the mouse clicked, and the anchor and focus are set
|
| - * to the boundaries of the selection.
|
| - *
|
| - * The only way to set the selection and give it direction is to use
|
| - * the non-standard Selection.setBaseAndExtent method. If you try to use
|
| - * Selection.addRange(), the anchor will always be on the left and the focus
|
| - * will always be on the right, making it impossible to manipulate
|
| - * selections that move from right to left.
|
| - *
|
| - * Finally, Chrome will throw an exception if you try to set an invalid
|
| - * selection - a selection where the left and right edges are not the same,
|
| - * but it doesn't span any visible characters. A common example is that
|
| - * there are often many whitespace characters in the DOM that are not
|
| - * visible on the page; trying to select them will fail. Another example is
|
| - * any node that's invisible or not displayed.
|
| - *
|
| - * While there are probably many possible methods to determine what is
|
| - * selectable, this code uses the method of determining if there's a valid
|
| - * bounding box for the range or not - keep moving the cursor forwards until
|
| - * the range from the previous position and candidate next position has a
|
| - * valid bounding box.
|
| - */
|
| -
|
| -/**
|
| - * Return whether a node is focusable. This includes nodes whose tabindex
|
| - * attribute is set to "-1" explicitly - these nodes are not in the tab
|
| - * order, but they should still be focused if the user navigates to them
|
| - * using linear or smart DOM navigation.
|
| - *
|
| - * Note that when the tabIndex property of an Element is -1, that doesn't
|
| - * tell us whether the tabIndex attribute is missing or set to "-1" explicitly,
|
| - * so we have to check the attribute.
|
| - *
|
| - * @param {Object} targetNode The node to check if it's focusable.
|
| - * @return {boolean} True if the node is focusable.
|
| - */
|
| -function isFocusable(targetNode) {
|
| - if (!targetNode || typeof(targetNode.tabIndex) != 'number') {
|
| - return false;
|
| - }
|
| -
|
| - if (targetNode.tabIndex >= 0) {
|
| - return true;
|
| - }
|
| -
|
| - if (targetNode.hasAttribute &&
|
| - targetNode.hasAttribute('tabindex') &&
|
| - targetNode.getAttribute('tabindex') == '-1') {
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -/**
|
| - * Determines whether or not a node is or is the descendant of another node.
|
| - *
|
| - * @param {Object} node The node to be checked.
|
| - * @param {Object} ancestor The node to see if it's a descendant of.
|
| - * @return {boolean} True if the node is ancestor or is a descendant of it.
|
| - */
|
| -function isDescendantOfNode(node, ancestor) {
|
| - while (node && ancestor) {
|
| - if (node.isSameNode(ancestor)) {
|
| - return true;
|
| - }
|
| - node = node.parentNode;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -
|
| -
|
| -/**
|
| - * The class handling the Caret Browsing implementation in the page.
|
| - * Installs a keydown listener that always responds to the F7 key,
|
| - * sets up communication with the background page, and then when caret
|
| - * browsing is enabled, response to various key events to move the caret
|
| - * or selection within the text content of the document. Uses the native
|
| - * Chrome selection wherever possible, but displays its own flashing
|
| - * caret using a DIV because there's no native caret available.
|
| - * @constructor
|
| - */
|
| -var CaretBrowsing = function() {};
|
| -
|
| -/**
|
| - * Is caret browsing enabled?
|
| - * @type {boolean}
|
| - */
|
| -CaretBrowsing.isEnabled = false;
|
| -
|
| -/**
|
| - * Keep it enabled even when flipped off (for the options page)?
|
| - * @type {boolean}
|
| - */
|
| -CaretBrowsing.forceEnabled = false;
|
| -
|
| -/**
|
| - * What to do when the caret appears?
|
| - * @type {string}
|
| - */
|
| -CaretBrowsing.onEnable;
|
| -
|
| -/**
|
| - * What to do when the caret jumps?
|
| - * @type {string}
|
| - */
|
| -CaretBrowsing.onJump;
|
| -
|
| -/**
|
| - * Is this window / iframe focused? We won't show the caret if not,
|
| - * especially so that carets aren't shown in two iframes of the same
|
| - * tab.
|
| - * @type {boolean}
|
| - */
|
| -CaretBrowsing.isWindowFocused = false;
|
| -
|
| -/**
|
| - * Is the caret actually visible? This is true only if isEnabled and
|
| - * isWindowFocused are both true.
|
| - * @type {boolean}
|
| - */
|
| -CaretBrowsing.isCaretVisible = false;
|
| -
|
| -/**
|
| - * The actual caret element, an absolute-positioned flashing line.
|
| - * @type {Element}
|
| - */
|
| -CaretBrowsing.caretElement;
|
| -
|
| -/**
|
| - * The x-position of the caret, in absolute pixels.
|
| - * @type {number}
|
| - */
|
| -CaretBrowsing.caretX = 0;
|
| -
|
| -/**
|
| - * The y-position of the caret, in absolute pixels.
|
| - * @type {number}
|
| - */
|
| -CaretBrowsing.caretY = 0;
|
| -
|
| -/**
|
| - * The width of the caret in pixels.
|
| - * @type {number}
|
| - */
|
| -CaretBrowsing.caretWidth = 0;
|
| -
|
| -/**
|
| - * The height of the caret in pixels.
|
| - * @type {number}
|
| - */
|
| -CaretBrowsing.caretHeight = 0;
|
| -
|
| -/**
|
| - * The foregroundc color.
|
| - * @type {string}
|
| - */
|
| -CaretBrowsing.caretForeground = '#000';
|
| -
|
| -/**
|
| - * The backgroundc color.
|
| - * @type {string}
|
| - */
|
| -CaretBrowsing.caretBackground = '#fff';
|
| -
|
| -/**
|
| - * Is the selection collapsed, i.e. are the start and end locations
|
| - * the same? If so, our blinking caret image is shown; otherwise
|
| - * the Chrome selection is shown.
|
| - * @type {boolean}
|
| - */
|
| -CaretBrowsing.isSelectionCollapsed = false;
|
| -
|
| -/**
|
| - * The id returned by window.setInterval for our blink function, so
|
| - * we can cancel it when caret browsing is disabled.
|
| - * @type {number?}
|
| - */
|
| -CaretBrowsing.blinkFunctionId = null;
|
| -
|
| -/**
|
| - * The desired x-coordinate to match when moving the caret up and down.
|
| - * To match the behavior as documented in Mozilla's caret browsing spec
|
| - * (http://www.mozilla.org/access/keyboard/proposal), we keep track of the
|
| - * initial x position when the user starts moving the caret up and down,
|
| - * so that the x position doesn't drift as you move throughout lines, but
|
| - * stays as close as possible to the initial position. This is reset when
|
| - * moving left or right or clicking.
|
| - * @type {number?}
|
| - */
|
| -CaretBrowsing.targetX = null;
|
| -
|
| -/**
|
| - * A flag that flips on or off as the caret blinks.
|
| - * @type {boolean}
|
| - */
|
| -CaretBrowsing.blinkFlag = true;
|
| -
|
| -/**
|
| - * Whether or not we're on a Mac - affects modifier keys.
|
| - * @type {boolean}
|
| - */
|
| -CaretBrowsing.isMac = (navigator.appVersion.indexOf("Mac") != -1);
|
| -
|
| -/**
|
| - * Check if a node is a control that normally allows the user to interact
|
| - * with it using arrow keys. We won't override the arrow keys when such a
|
| - * control has focus, the user must press Escape to do caret browsing outside
|
| - * that control.
|
| - * @param {Node} node A node to check.
|
| - * @return {boolean} True if this node is a control that the user can
|
| - * interact with using arrow keys.
|
| - */
|
| -CaretBrowsing.isControlThatNeedsArrowKeys = function(node) {
|
| - if (!node) {
|
| - return false;
|
| - }
|
| -
|
| - if (node == document.body || node != document.activeElement) {
|
| - return false;
|
| - }
|
| -
|
| - if (node.constructor == HTMLSelectElement) {
|
| - return true;
|
| - }
|
| -
|
| - if (node.constructor == HTMLInputElement) {
|
| - switch (node.type) {
|
| - case 'email':
|
| - case 'number':
|
| - case 'password':
|
| - case 'search':
|
| - case 'text':
|
| - case 'tel':
|
| - case 'url':
|
| - case '':
|
| - return true; // All of these are text boxes.
|
| - case 'datetime':
|
| - case 'datetime-local':
|
| - case 'date':
|
| - case 'month':
|
| - case 'radio':
|
| - case 'range':
|
| - case 'week':
|
| - return true; // These are other input elements that use arrows.
|
| - }
|
| - }
|
| -
|
| - // Handle focusable ARIA controls.
|
| - if (node.getAttribute && isFocusable(node)) {
|
| - var role = node.getAttribute('role');
|
| - switch (role) {
|
| - case 'combobox':
|
| - case 'grid':
|
| - case 'gridcell':
|
| - case 'listbox':
|
| - case 'menu':
|
| - case 'menubar':
|
| - case 'menuitem':
|
| - case 'menuitemcheckbox':
|
| - case 'menuitemradio':
|
| - case 'option':
|
| - case 'radiogroup':
|
| - case 'scrollbar':
|
| - case 'slider':
|
| - case 'spinbutton':
|
| - case 'tab':
|
| - case 'tablist':
|
| - case 'textbox':
|
| - case 'tree':
|
| - case 'treegrid':
|
| - case 'treeitem':
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -};
|
| -
|
| -/**
|
| - * If there's no initial selection, set the cursor just before the
|
| - * first text character in the document.
|
| - */
|
| -CaretBrowsing.setInitialCursor = function() {
|
| - var sel = window.getSelection();
|
| - if (sel.rangeCount > 0) {
|
| - return;
|
| - }
|
| -
|
| - var start = new Cursor(document.body, 0, '');
|
| - var end = new Cursor(document.body, 0, '');
|
| - var nodesCrossed = [];
|
| - var result = TraverseUtil.getNextChar(start, end, nodesCrossed, true);
|
| - if (result == null) {
|
| - return;
|
| - }
|
| - CaretBrowsing.setAndValidateSelection(start, start);
|
| -};
|
| -
|
| -/**
|
| - * Set focus to a node if it's focusable. If it's an input element,
|
| - * select the text, otherwise it doesn't appear focused to the user.
|
| - * Every other control behaves normally if you just call focus() on it.
|
| - * @param {Node} node The node to focus.
|
| - * @return {boolean} True if the node was focused.
|
| - */
|
| -CaretBrowsing.setFocusToNode = function(node) {
|
| - while (node && node != document.body) {
|
| - if (isFocusable(node) && node.constructor != HTMLIFrameElement) {
|
| - node.focus();
|
| - if (node.constructor == HTMLInputElement && node.select) {
|
| - node.select();
|
| - }
|
| - return true;
|
| - }
|
| - node = node.parentNode;
|
| - }
|
| -
|
| - return false;
|
| -};
|
| -
|
| -/**
|
| - * Set focus to the first focusable node in the given list.
|
| - * select the text, otherwise it doesn't appear focused to the user.
|
| - * Every other control behaves normally if you just call focus() on it.
|
| - * @param {Array.<Node>} nodeList An array of nodes to focus.
|
| - * @return {boolean} True if the node was focused.
|
| - */
|
| -CaretBrowsing.setFocusToFirstFocusable = function(nodeList) {
|
| - for (var i = 0; i < nodeList.length; i++) {
|
| - if (CaretBrowsing.setFocusToNode(nodeList[i])) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -};
|
| -
|
| -/**
|
| - * Set the caret element's normal style, i.e. not when animating.
|
| - */
|
| -CaretBrowsing.setCaretElementNormalStyle = function() {
|
| - var element = CaretBrowsing.caretElement;
|
| - element.className = 'CaretBrowsing_Caret';
|
| - element.style.opacity = CaretBrowsing.isSelectionCollapsed ? '1.0' : '0.0';
|
| - element.style.left = CaretBrowsing.caretX + 'px';
|
| - element.style.top = CaretBrowsing.caretY + 'px';
|
| - element.style.width = CaretBrowsing.caretWidth + 'px';
|
| - element.style.height = CaretBrowsing.caretHeight + 'px';
|
| - element.style.color = CaretBrowsing.caretForeground;
|
| -};
|
| -
|
| -/**
|
| - * Animate the caret element into the normal style.
|
| - */
|
| -CaretBrowsing.animateCaretElement = function() {
|
| - var element = CaretBrowsing.caretElement;
|
| - element.style.left = (CaretBrowsing.caretX - 50) + 'px';
|
| - element.style.top = (CaretBrowsing.caretY - 100) + 'px';
|
| - element.style.width = (CaretBrowsing.caretWidth + 100) + 'px';
|
| - element.style.height = (CaretBrowsing.caretHeight + 200) + 'px';
|
| - element.className = 'CaretBrowsing_AnimateCaret';
|
| -
|
| - // Start the animation. The setTimeout is so that the old values will get
|
| - // applied first, so we can animate to the new values.
|
| - window.setTimeout(function() {
|
| - if (!CaretBrowsing.caretElement) {
|
| - return;
|
| - }
|
| - CaretBrowsing.setCaretElementNormalStyle();
|
| - element.style['-webkit-transition'] = 'all 0.8s ease-in';
|
| - function listener() {
|
| - element.removeEventListener(
|
| - 'webkitTransitionEnd', listener, false);
|
| - element.style['-webkit-transition'] = 'none';
|
| - }
|
| - element.addEventListener(
|
| - 'webkitTransitionEnd', listener, false);
|
| - }, 0);
|
| -};
|
| -
|
| -/**
|
| - * Quick flash and then show the normal caret style.
|
| - */
|
| -CaretBrowsing.flashCaretElement = function() {
|
| - var x = CaretBrowsing.caretX - window.pageXOffset;
|
| - var y = CaretBrowsing.caretY - window.pageYOffset;
|
| - var height = CaretBrowsing.caretHeight;
|
| -
|
| - var vert = document.createElement('div');
|
| - vert.className = 'CaretBrowsing_FlashVert';
|
| - vert.style.left = (x - 6) + 'px';
|
| - vert.style.top = (y - 100) + 'px';
|
| - vert.style.width = '11px';
|
| - vert.style.height = (200) + 'px';
|
| - document.body.appendChild(vert);
|
| -
|
| - window.setTimeout(function() {
|
| - document.body.removeChild(vert);
|
| - if (CaretBrowsing.caretElement) {
|
| - CaretBrowsing.setCaretElementNormalStyle();
|
| - }
|
| - }, 250);
|
| -};
|
| -
|
| -/**
|
| - * Create the caret element. This assumes that caretX, caretY,
|
| - * caretWidth, and caretHeight have all been set. The caret is
|
| - * animated in so the user can find it when it first appears.
|
| - */
|
| -CaretBrowsing.createCaretElement = function() {
|
| - var element = document.createElement('div');
|
| - element.className = 'CaretBrowsing_Caret';
|
| - document.body.appendChild(element);
|
| - CaretBrowsing.caretElement = element;
|
| -
|
| - if (CaretBrowsing.onEnable == 'anim') {
|
| - CaretBrowsing.animateCaretElement();
|
| - } else if (CaretBrowsing.onEnable == 'flash') {
|
| - CaretBrowsing.flashCaretElement();
|
| - } else {
|
| - CaretBrowsing.setCaretElementNormalStyle();
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Recreate the caret element, triggering any intro animation.
|
| - */
|
| -CaretBrowsing.recreateCaretElement = function() {
|
| - if (CaretBrowsing.caretElement) {
|
| - window.clearInterval(CaretBrowsing.blinkFunctionId);
|
| - CaretBrowsing.caretElement.parentElement.removeChild(
|
| - CaretBrowsing.caretElement);
|
| - CaretBrowsing.caretElement = null;
|
| - CaretBrowsing.updateIsCaretVisible();
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Get the rectangle for a cursor position. This is tricky because
|
| - * you can't get the bounding rectangle of an empty range, so this function
|
| - * computes the rect by trying a range including one character earlier or
|
| - * later than the cursor position.
|
| - * @param {Cursor} cursor A single cursor position.
|
| - * @return {{left: number, top: number, width: number, height: number}}
|
| - * The bounding rectangle of the cursor.
|
| - */
|
| -CaretBrowsing.getCursorRect = function(cursor) {
|
| - var node = cursor.node;
|
| - var index = cursor.index;
|
| - var rect = {
|
| - left: 0,
|
| - top: 0,
|
| - width: 1,
|
| - height: 0
|
| - };
|
| - if (node.constructor == Text) {
|
| - var left = index;
|
| - var right = index;
|
| - var max = node.data.length;
|
| - var newRange = document.createRange();
|
| - while (left > 0 || right < max) {
|
| - if (left > 0) {
|
| - left--;
|
| - newRange.setStart(node, left);
|
| - newRange.setEnd(node, index);
|
| - var rangeRect = newRange.getBoundingClientRect();
|
| - if (rangeRect && rangeRect.width && rangeRect.height) {
|
| - rect.left = rangeRect.right;
|
| - rect.top = rangeRect.top;
|
| - rect.height = rangeRect.height;
|
| - break;
|
| - }
|
| - }
|
| - if (right < max) {
|
| - right++;
|
| - newRange.setStart(node, index);
|
| - newRange.setEnd(node, right);
|
| - var rangeRect = newRange.getBoundingClientRect();
|
| - if (rangeRect && rangeRect.width && rangeRect.height) {
|
| - rect.left = rangeRect.left;
|
| - rect.top = rangeRect.top;
|
| - rect.height = rangeRect.height;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - } else {
|
| - rect.height = node.offsetHeight;
|
| - while (node !== null) {
|
| - rect.left += node.offsetLeft;
|
| - rect.top += node.offsetTop;
|
| - node = node.offsetParent;
|
| - }
|
| - }
|
| - rect.left += window.pageXOffset;
|
| - rect.top += window.pageYOffset;
|
| - return rect;
|
| -};
|
| -
|
| -/**
|
| - * Compute the new location of the caret or selection and update
|
| - * the element as needed.
|
| - * @param {boolean} scrollToSelection If true, will also scroll the page
|
| - * to the caret / selection location.
|
| - */
|
| -CaretBrowsing.updateCaretOrSelection = function(scrollToSelection) {
|
| - var previousX = CaretBrowsing.caretX;
|
| - var previousY = CaretBrowsing.caretY;
|
| -
|
| - var sel = window.getSelection();
|
| - if (sel.rangeCount == 0) {
|
| - if (CaretBrowsing.caretElement) {
|
| - CaretBrowsing.isSelectionCollapsed = false;
|
| - CaretBrowsing.caretElement.style.opacity = '0.0';
|
| - }
|
| - return;
|
| - }
|
| -
|
| - var range = sel.getRangeAt(0);
|
| - if (!range) {
|
| - if (CaretBrowsing.caretElement) {
|
| - CaretBrowsing.isSelectionCollapsed = false;
|
| - CaretBrowsing.caretElement.style.opacity = '0.0';
|
| - }
|
| - return;
|
| - }
|
| -
|
| - if (CaretBrowsing.isControlThatNeedsArrowKeys(document.activeElement)) {
|
| - var node = document.activeElement;
|
| - CaretBrowsing.caretWidth = node.offsetWidth;
|
| - CaretBrowsing.caretHeight = node.offsetHeight;
|
| - CaretBrowsing.caretX = 0;
|
| - CaretBrowsing.caretY = 0;
|
| - while (node.offsetParent) {
|
| - CaretBrowsing.caretX += node.offsetLeft;
|
| - CaretBrowsing.caretY += node.offsetTop;
|
| - node = node.offsetParent;
|
| - }
|
| - CaretBrowsing.isSelectionCollapsed = false;
|
| - } else if (range.startOffset != range.endOffset ||
|
| - range.startContainer != range.endContainer) {
|
| - var rect = range.getBoundingClientRect();
|
| - if (!rect) {
|
| - return;
|
| - }
|
| - CaretBrowsing.caretX = rect.left + window.pageXOffset;
|
| - CaretBrowsing.caretY = rect.top + window.pageYOffset;
|
| - CaretBrowsing.caretWidth = rect.width;
|
| - CaretBrowsing.caretHeight = rect.height;
|
| - CaretBrowsing.isSelectionCollapsed = false;
|
| - } else {
|
| - var rect = CaretBrowsing.getCursorRect(
|
| - new Cursor(range.startContainer,
|
| - range.startOffset,
|
| - TraverseUtil.getNodeText(range.startContainer)));
|
| - CaretBrowsing.caretX = rect.left;
|
| - CaretBrowsing.caretY = rect.top;
|
| - CaretBrowsing.caretWidth = rect.width;
|
| - CaretBrowsing.caretHeight = rect.height;
|
| - CaretBrowsing.isSelectionCollapsed = true;
|
| - }
|
| -
|
| - if (!CaretBrowsing.caretElement) {
|
| - CaretBrowsing.createCaretElement();
|
| - } else {
|
| - var element = CaretBrowsing.caretElement;
|
| - if (CaretBrowsing.isSelectionCollapsed) {
|
| - element.style.opacity = '1.0';
|
| - element.style.left = CaretBrowsing.caretX + 'px';
|
| - element.style.top = CaretBrowsing.caretY + 'px';
|
| - element.style.width = CaretBrowsing.caretWidth + 'px';
|
| - element.style.height = CaretBrowsing.caretHeight + 'px';
|
| - } else {
|
| - element.style.opacity = '0.0';
|
| - }
|
| - }
|
| -
|
| - var elem = range.startContainer;
|
| - if (elem.constructor == Text)
|
| - elem = elem.parentElement;
|
| - var style = window.getComputedStyle(elem);
|
| - var bg = axs.utils.getBgColor(style, elem);
|
| - var fg = axs.utils.getFgColor(style, elem, bg);
|
| - CaretBrowsing.caretBackground = axs.utils.colorToString(bg);
|
| - CaretBrowsing.caretForeground = axs.utils.colorToString(fg);
|
| -
|
| - if (scrollToSelection) {
|
| - // Scroll just to the "focus" position of the selection,
|
| - // the part the user is manipulating.
|
| - var rect = CaretBrowsing.getCursorRect(
|
| - new Cursor(sel.focusNode, sel.focusOffset,
|
| - TraverseUtil.getNodeText(sel.focusNode)));
|
| -
|
| - var yscroll = window.pageYOffset;
|
| - var pageHeight = window.innerHeight;
|
| - var caretY = rect.top;
|
| - var caretHeight = Math.min(rect.height, 30);
|
| - if (yscroll + pageHeight < caretY + caretHeight) {
|
| - window.scroll(0, (caretY + caretHeight - pageHeight + 100));
|
| - } else if (caretY < yscroll) {
|
| - window.scroll(0, (caretY - 100));
|
| - }
|
| - }
|
| -
|
| - if (Math.abs(previousX - CaretBrowsing.caretX) > 500 ||
|
| - Math.abs(previousY - CaretBrowsing.caretY) > 100) {
|
| - if (CaretBrowsing.onJump == 'anim') {
|
| - CaretBrowsing.animateCaretElement();
|
| - } else if (CaretBrowsing.onJump == 'flash') {
|
| - CaretBrowsing.flashCaretElement();
|
| - }
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Return true if the selection directionality is ambiguous, which happens
|
| - * if, for example, the user double-clicks in the middle of a word to select
|
| - * it. In that case, the selection should extend by the right edge if the
|
| - * user presses right, and by the left edge if the user presses left.
|
| - * @param {Selection} sel The selection.
|
| - * @return {boolean} True if the selection directionality is ambiguous.
|
| - */
|
| -CaretBrowsing.isAmbiguous = function(sel) {
|
| - return (sel.anchorNode != sel.baseNode ||
|
| - sel.anchorOffset != sel.baseOffset ||
|
| - sel.focusNode != sel.extentNode ||
|
| - sel.focusOffset != sel.extentOffset);
|
| -};
|
| -
|
| -/**
|
| - * Create a Cursor from the anchor position of the selection, the
|
| - * part that doesn't normally move.
|
| - * @param {Selection} sel The selection.
|
| - * @return {Cursor} A cursor pointing to the selection's anchor location.
|
| - */
|
| -CaretBrowsing.makeAnchorCursor = function(sel) {
|
| - return new Cursor(sel.anchorNode, sel.anchorOffset,
|
| - TraverseUtil.getNodeText(sel.anchorNode));
|
| -};
|
| -
|
| -/**
|
| - * Create a Cursor from the focus position of the selection.
|
| - * @param {Selection} sel The selection.
|
| - * @return {Cursor} A cursor pointing to the selection's focus location.
|
| - */
|
| -CaretBrowsing.makeFocusCursor = function(sel) {
|
| - return new Cursor(sel.focusNode, sel.focusOffset,
|
| - TraverseUtil.getNodeText(sel.focusNode));
|
| -};
|
| -
|
| -/**
|
| - * Create a Cursor from the left boundary of the selection - the boundary
|
| - * closer to the start of the document.
|
| - * @param {Selection} sel The selection.
|
| - * @return {Cursor} A cursor pointing to the selection's left boundary.
|
| - */
|
| -CaretBrowsing.makeLeftCursor = function(sel) {
|
| - var range = sel.rangeCount == 1 ? sel.getRangeAt(0) : null;
|
| - if (range &&
|
| - range.endContainer == sel.anchorNode &&
|
| - range.endOffset == sel.anchorOffset) {
|
| - return CaretBrowsing.makeFocusCursor(sel);
|
| - } else {
|
| - return CaretBrowsing.makeAnchorCursor(sel);
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Create a Cursor from the right boundary of the selection - the boundary
|
| - * closer to the end of the document.
|
| - * @param {Selection} sel The selection.
|
| - * @return {Cursor} A cursor pointing to the selection's right boundary.
|
| - */
|
| -CaretBrowsing.makeRightCursor = function(sel) {
|
| - var range = sel.rangeCount == 1 ? sel.getRangeAt(0) : null;
|
| - if (range &&
|
| - range.endContainer == sel.anchorNode &&
|
| - range.endOffset == sel.anchorOffset) {
|
| - return CaretBrowsing.makeAnchorCursor(sel);
|
| - } else {
|
| - return CaretBrowsing.makeFocusCursor(sel);
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Try to set the window's selection to be between the given start and end
|
| - * cursors, and return whether or not it was successful.
|
| - * @param {Cursor} start The start position.
|
| - * @param {Cursor} end The end position.
|
| - * @return {boolean} True if the selection was successfully set.
|
| - */
|
| -CaretBrowsing.setAndValidateSelection = function(start, end) {
|
| - var sel = window.getSelection();
|
| - sel.setBaseAndExtent(start.node, start.index, end.node, end.index);
|
| -
|
| - if (sel.rangeCount != 1) {
|
| - return false;
|
| - }
|
| -
|
| - return (sel.anchorNode == start.node &&
|
| - sel.anchorOffset == start.index &&
|
| - sel.focusNode == end.node &&
|
| - sel.focusOffset == end.index);
|
| -};
|
| -
|
| -/**
|
| - * Note: the built-in function by the same name is unreliable.
|
| - * @param {Selection} sel The selection.
|
| - * @return {boolean} True if the start and end positions are the same.
|
| - */
|
| -CaretBrowsing.isCollapsed = function(sel) {
|
| - return (sel.anchorOffset == sel.focusOffset &&
|
| - sel.anchorNode == sel.focusNode);
|
| -};
|
| -
|
| -/**
|
| - * Determines if the modifier key is held down that should cause
|
| - * the cursor to move by word rather than by character.
|
| - * @param {Event} evt A keyboard event.
|
| - * @return {boolean} True if the cursor should move by word.
|
| - */
|
| -CaretBrowsing.isMoveByWordEvent = function(evt) {
|
| - if (CaretBrowsing.isMac) {
|
| - return evt.altKey;
|
| - } else {
|
| - return evt.ctrlKey;
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Moves the cursor forwards to the next valid position.
|
| - * @param {Cursor} cursor The current cursor location.
|
| - * On exit, the cursor will be at the next position.
|
| - * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
|
| - * initial and final cursor position will be pushed onto this array.
|
| - * @return {?string} The character reached, or null if the bottom of the
|
| - * document has been reached.
|
| - */
|
| -CaretBrowsing.forwards = function(cursor, nodesCrossed) {
|
| - var previousCursor = cursor.clone();
|
| - var result = TraverseUtil.forwardsChar(cursor, nodesCrossed);
|
| -
|
| - // Work around the fact that TraverseUtil.forwardsChar returns once per
|
| - // char in a block of text, rather than once per possible selection
|
| - // position in a block of text.
|
| - if (result && cursor.node != previousCursor.node && cursor.index > 0) {
|
| - cursor.index = 0;
|
| - }
|
| -
|
| - return result;
|
| -};
|
| -
|
| -/**
|
| - * Moves the cursor backwards to the previous valid position.
|
| - * @param {Cursor} cursor The current cursor location.
|
| - * On exit, the cursor will be at the previous position.
|
| - * @param {Array.<Node>} nodesCrossed Any HTML nodes crossed between the
|
| - * initial and final cursor position will be pushed onto this array.
|
| - * @return {?string} The character reached, or null if the top of the
|
| - * document has been reached.
|
| - */
|
| -CaretBrowsing.backwards = function(cursor, nodesCrossed) {
|
| - var previousCursor = cursor.clone();
|
| - var result = TraverseUtil.backwardsChar(cursor, nodesCrossed);
|
| -
|
| - // Work around the fact that TraverseUtil.backwardsChar returns once per
|
| - // char in a block of text, rather than once per possible selection
|
| - // position in a block of text.
|
| - if (result &&
|
| - cursor.node != previousCursor.node &&
|
| - cursor.index < cursor.text.length) {
|
| - cursor.index = cursor.text.length;
|
| - }
|
| -
|
| - return result;
|
| -};
|
| -
|
| -/**
|
| - * Called when the user presses the right arrow. If there's a selection,
|
| - * moves the cursor to the end of the selection range. If it's a cursor,
|
| - * moves past one character.
|
| - * @param {Event} evt The DOM event.
|
| - * @return {boolean} True if the default action should be performed.
|
| - */
|
| -CaretBrowsing.moveRight = function(evt) {
|
| - CaretBrowsing.targetX = null;
|
| -
|
| - var sel = window.getSelection();
|
| - if (!evt.shiftKey && !CaretBrowsing.isCollapsed(sel)) {
|
| - var right = CaretBrowsing.makeRightCursor(sel);
|
| - CaretBrowsing.setAndValidateSelection(right, right);
|
| - return false;
|
| - }
|
| -
|
| - var start = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeLeftCursor(sel) :
|
| - CaretBrowsing.makeAnchorCursor(sel);
|
| - var end = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeRightCursor(sel) :
|
| - CaretBrowsing.makeFocusCursor(sel);
|
| - var previousEnd = end.clone();
|
| - var nodesCrossed = [];
|
| - while (true) {
|
| - var result;
|
| - if (CaretBrowsing.isMoveByWordEvent(evt)) {
|
| - result = TraverseUtil.getNextWord(previousEnd, end, nodesCrossed);
|
| - } else {
|
| - previousEnd = end.clone();
|
| - result = CaretBrowsing.forwards(end, nodesCrossed);
|
| - }
|
| -
|
| - if (result === null) {
|
| - return CaretBrowsing.moveLeft(evt);
|
| - }
|
| -
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? start : end, end)) {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (!evt.shiftKey) {
|
| - nodesCrossed.push(end.node);
|
| - CaretBrowsing.setFocusToFirstFocusable(nodesCrossed);
|
| - }
|
| -
|
| - return false;
|
| -};
|
| -
|
| -/**
|
| - * Called when the user presses the left arrow. If there's a selection,
|
| - * moves the cursor to the start of the selection range. If it's a cursor,
|
| - * moves backwards past one character.
|
| - * @param {Event} evt The DOM event.
|
| - * @return {boolean} True if the default action should be performed.
|
| - */
|
| -CaretBrowsing.moveLeft = function(evt) {
|
| - CaretBrowsing.targetX = null;
|
| -
|
| - var sel = window.getSelection();
|
| - if (!evt.shiftKey && !CaretBrowsing.isCollapsed(sel)) {
|
| - var left = CaretBrowsing.makeLeftCursor(sel);
|
| - CaretBrowsing.setAndValidateSelection(left, left);
|
| - return false;
|
| - }
|
| -
|
| - var start = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeLeftCursor(sel) :
|
| - CaretBrowsing.makeFocusCursor(sel);
|
| - var end = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeRightCursor(sel) :
|
| - CaretBrowsing.makeAnchorCursor(sel);
|
| - var previousStart = start.clone();
|
| - var nodesCrossed = [];
|
| - while (true) {
|
| - var result;
|
| - if (CaretBrowsing.isMoveByWordEvent(evt)) {
|
| - result = TraverseUtil.getPreviousWord(
|
| - start, previousStart, nodesCrossed);
|
| - } else {
|
| - previousStart = start.clone();
|
| - result = CaretBrowsing.backwards(start, nodesCrossed);
|
| - }
|
| -
|
| - if (result === null) {
|
| - break;
|
| - }
|
| -
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? end : start, start)) {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (!evt.shiftKey) {
|
| - nodesCrossed.push(start.node);
|
| - CaretBrowsing.setFocusToFirstFocusable(nodesCrossed);
|
| - }
|
| -
|
| - return false;
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Called when the user presses the down arrow. If there's a selection,
|
| - * moves the cursor to the end of the selection range. If it's a cursor,
|
| - * attempts to move to the equivalent horizontal pixel position in the
|
| - * subsequent line of text. If this is impossible, go to the first character
|
| - * of the next line.
|
| - * @param {Event} evt The DOM event.
|
| - * @return {boolean} True if the default action should be performed.
|
| - */
|
| -CaretBrowsing.moveDown = function(evt) {
|
| - var sel = window.getSelection();
|
| - if (!evt.shiftKey && !CaretBrowsing.isCollapsed(sel)) {
|
| - var right = CaretBrowsing.makeRightCursor(sel);
|
| - CaretBrowsing.setAndValidateSelection(right, right);
|
| - return false;
|
| - }
|
| -
|
| - var start = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeLeftCursor(sel) :
|
| - CaretBrowsing.makeAnchorCursor(sel);
|
| - var end = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeRightCursor(sel) :
|
| - CaretBrowsing.makeFocusCursor(sel);
|
| - var endRect = CaretBrowsing.getCursorRect(end);
|
| - if (CaretBrowsing.targetX === null) {
|
| - CaretBrowsing.targetX = endRect.left;
|
| - }
|
| - var previousEnd = end.clone();
|
| - var leftPos = end.clone();
|
| - var rightPos = end.clone();
|
| - var bestPos = null;
|
| - var bestY = null;
|
| - var bestDelta = null;
|
| - var bestHeight = null;
|
| - var nodesCrossed = [];
|
| - var y = -1;
|
| - while (true) {
|
| - if (null === CaretBrowsing.forwards(rightPos, nodesCrossed)) {
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? start : leftPos, leftPos)) {
|
| - break;
|
| - } else {
|
| - return CaretBrowsing.moveLeft(evt);
|
| - }
|
| - break;
|
| - }
|
| - var range = document.createRange();
|
| - range.setStart(leftPos.node, leftPos.index);
|
| - range.setEnd(rightPos.node, rightPos.index);
|
| - var rect = range.getBoundingClientRect();
|
| - if (rect && rect.width < rect.height) {
|
| - y = rect.top + window.pageYOffset;
|
| -
|
| - // Return the best match so far if we get half a line past the best.
|
| - if (bestY != null && y > bestY + bestHeight / 2) {
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? start : bestPos, bestPos)) {
|
| - break;
|
| - } else {
|
| - bestY = null;
|
| - }
|
| - }
|
| -
|
| - // Stop here if we're an entire line the wrong direction
|
| - // (for example, we reached the top of the next column).
|
| - if (y < endRect.top - endRect.height) {
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? start : leftPos, leftPos)) {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - // Otherwise look to see if this current position is on the
|
| - // next line and better than the previous best match, if any.
|
| - if (y >= endRect.top + endRect.height) {
|
| - var deltaLeft = Math.abs(CaretBrowsing.targetX - rect.left);
|
| - if ((bestDelta == null || deltaLeft < bestDelta) &&
|
| - (leftPos.node != end.node || leftPos.index != end.index)) {
|
| - bestPos = leftPos.clone();
|
| - bestY = y;
|
| - bestDelta = deltaLeft;
|
| - bestHeight = rect.height;
|
| - }
|
| - var deltaRight = Math.abs(CaretBrowsing.targetX - rect.right);
|
| - if (bestDelta == null || deltaRight < bestDelta) {
|
| - bestPos = rightPos.clone();
|
| - bestY = y;
|
| - bestDelta = deltaRight;
|
| - bestHeight = rect.height;
|
| - }
|
| -
|
| - // Return the best match so far if the deltas are getting worse,
|
| - // not better.
|
| - if (bestDelta != null &&
|
| - deltaLeft > bestDelta &&
|
| - deltaRight > bestDelta) {
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? start : bestPos, bestPos)) {
|
| - break;
|
| - } else {
|
| - bestY = null;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - leftPos = rightPos.clone();
|
| - }
|
| -
|
| - if (!evt.shiftKey) {
|
| - CaretBrowsing.setFocusToNode(leftPos.node);
|
| - }
|
| -
|
| - return false;
|
| -};
|
| -
|
| -/**
|
| - * Called when the user presses the up arrow. If there's a selection,
|
| - * moves the cursor to the start of the selection range. If it's a cursor,
|
| - * attempts to move to the equivalent horizontal pixel position in the
|
| - * previous line of text. If this is impossible, go to the last character
|
| - * of the previous line.
|
| - * @param {Event} evt The DOM event.
|
| - * @return {boolean} True if the default action should be performed.
|
| - */
|
| -CaretBrowsing.moveUp = function(evt) {
|
| - var sel = window.getSelection();
|
| - if (!evt.shiftKey && !CaretBrowsing.isCollapsed(sel)) {
|
| - var left = CaretBrowsing.makeLeftCursor(sel);
|
| - CaretBrowsing.setAndValidateSelection(left, left);
|
| - return false;
|
| - }
|
| -
|
| - var start = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeLeftCursor(sel) :
|
| - CaretBrowsing.makeFocusCursor(sel);
|
| - var end = CaretBrowsing.isAmbiguous(sel) ?
|
| - CaretBrowsing.makeRightCursor(sel) :
|
| - CaretBrowsing.makeAnchorCursor(sel);
|
| - var startRect = CaretBrowsing.getCursorRect(start);
|
| - if (CaretBrowsing.targetX === null) {
|
| - CaretBrowsing.targetX = startRect.left;
|
| - }
|
| - var previousStart = start.clone();
|
| - var leftPos = start.clone();
|
| - var rightPos = start.clone();
|
| - var bestPos = null;
|
| - var bestY = null;
|
| - var bestDelta = null;
|
| - var bestHeight = null;
|
| - var nodesCrossed = [];
|
| - var y = 999999;
|
| - while (true) {
|
| - if (null === CaretBrowsing.backwards(leftPos, nodesCrossed)) {
|
| - CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? end : rightPos, rightPos);
|
| - break;
|
| - }
|
| - var range = document.createRange();
|
| - range.setStart(leftPos.node, leftPos.index);
|
| - range.setEnd(rightPos.node, rightPos.index);
|
| - var rect = range.getBoundingClientRect();
|
| - if (rect && rect.width < rect.height) {
|
| - y = rect.top + window.pageYOffset;
|
| -
|
| - // Return the best match so far if we get half a line past the best.
|
| - if (bestY != null && y < bestY - bestHeight / 2) {
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? end : bestPos, bestPos)) {
|
| - break;
|
| - } else {
|
| - bestY = null;
|
| - }
|
| - }
|
| -
|
| - // Exit if we're an entire line the wrong direction
|
| - // (for example, we reached the bottom of the previous column.)
|
| - if (y > startRect.top + startRect.height) {
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? end : rightPos, rightPos)) {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - // Otherwise look to see if this current position is on the
|
| - // next line and better than the previous best match, if any.
|
| - if (y <= startRect.top - startRect.height) {
|
| - var deltaLeft = Math.abs(CaretBrowsing.targetX - rect.left);
|
| - if (bestDelta == null || deltaLeft < bestDelta) {
|
| - bestPos = leftPos.clone();
|
| - bestY = y;
|
| - bestDelta = deltaLeft;
|
| - bestHeight = rect.height;
|
| - }
|
| - var deltaRight = Math.abs(CaretBrowsing.targetX - rect.right);
|
| - if ((bestDelta == null || deltaRight < bestDelta) &&
|
| - (rightPos.node != start.node || rightPos.index != start.index)) {
|
| - bestPos = rightPos.clone();
|
| - bestY = y;
|
| - bestDelta = deltaRight;
|
| - bestHeight = rect.height;
|
| - }
|
| -
|
| - // Return the best match so far if the deltas are getting worse,
|
| - // not better.
|
| - if (bestDelta != null &&
|
| - deltaLeft > bestDelta &&
|
| - deltaRight > bestDelta) {
|
| - if (CaretBrowsing.setAndValidateSelection(
|
| - evt.shiftKey ? end : bestPos, bestPos)) {
|
| - break;
|
| - } else {
|
| - bestY = null;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - rightPos = leftPos.clone();
|
| - }
|
| -
|
| - if (!evt.shiftKey) {
|
| - CaretBrowsing.setFocusToNode(rightPos.node);
|
| - }
|
| -
|
| - return false;
|
| -};
|
| -
|
| -/**
|
| - * Set the document's selection to surround a control, so that the next
|
| - * arrow key they press will allow them to explore the content before
|
| - * or after a given control.
|
| - * @param {Node} control The control to escape from.
|
| - */
|
| -CaretBrowsing.escapeFromControl = function(control) {
|
| - control.blur();
|
| -
|
| - var start = new Cursor(control, 0, '');
|
| - var previousStart = start.clone();
|
| - var end = new Cursor(control, 0, '');
|
| - var previousEnd = end.clone();
|
| -
|
| - var nodesCrossed = [];
|
| - while (true) {
|
| - if (null === CaretBrowsing.backwards(start, nodesCrossed)) {
|
| - break;
|
| - }
|
| -
|
| - var r = document.createRange();
|
| - r.setStart(start.node, start.index);
|
| - r.setEnd(previousStart.node, previousStart.index);
|
| - if (r.getBoundingClientRect()) {
|
| - break;
|
| - }
|
| - previousStart = start.clone();
|
| - }
|
| - while (true) {
|
| - if (null === CaretBrowsing.forwards(end, nodesCrossed)) {
|
| - break;
|
| - }
|
| - if (isDescendantOfNode(end.node, control)) {
|
| - previousEnd = end.clone();
|
| - continue;
|
| - }
|
| -
|
| - var r = document.createRange();
|
| - r.setStart(previousEnd.node, previousEnd.index);
|
| - r.setEnd(end.node, end.index);
|
| - if (r.getBoundingClientRect()) {
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (!isDescendantOfNode(previousStart.node, control)) {
|
| - start = previousStart.clone();
|
| - }
|
| -
|
| - if (!isDescendantOfNode(previousEnd.node, control)) {
|
| - end = previousEnd.clone();
|
| - }
|
| -
|
| - CaretBrowsing.setAndValidateSelection(start, end);
|
| -
|
| - window.setTimeout(function() {
|
| - CaretBrowsing.updateCaretOrSelection(true);
|
| - }, 0);
|
| -};
|
| -
|
| -/**
|
| - * Toggle whether caret browsing is enabled or not.
|
| - */
|
| -CaretBrowsing.toggle = function() {
|
| - if (CaretBrowsing.forceEnabled) {
|
| - CaretBrowsing.recreateCaretElement();
|
| - return;
|
| - }
|
| -
|
| - CaretBrowsing.isEnabled = !CaretBrowsing.isEnabled;
|
| - var obj = {};
|
| - obj['enabled'] = CaretBrowsing.isEnabled;
|
| - chrome.storage.sync.set(obj);
|
| - CaretBrowsing.updateIsCaretVisible();
|
| -};
|
| -
|
| -/**
|
| - * Event handler, called when a key is pressed.
|
| - * @param {Event} evt The DOM event.
|
| - * @return {boolean} True if the default action should be performed.
|
| - */
|
| -CaretBrowsing.onKeyDown = function(evt) {
|
| - if (evt.defaultPrevented) {
|
| - return;
|
| - }
|
| -
|
| - if (evt.keyCode == 118) { // F7
|
| - CaretBrowsing.toggle();
|
| - }
|
| -
|
| - if (!CaretBrowsing.isEnabled) {
|
| - return true;
|
| - }
|
| -
|
| - if (evt.target && CaretBrowsing.isControlThatNeedsArrowKeys(
|
| - /** @type (Node) */(evt.target))) {
|
| - if (evt.keyCode == 27) {
|
| - CaretBrowsing.escapeFromControl(/** @type {Node} */(evt.target));
|
| - evt.preventDefault();
|
| - evt.stopPropagation();
|
| - return false;
|
| - } else {
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - // If the current selection doesn't have a range, try to escape out of
|
| - // the current control. If that fails, return so we don't fail whe
|
| - // trying to move the cursor or selection.
|
| - var sel = window.getSelection();
|
| - if (sel.rangeCount == 0) {
|
| - if (document.activeElement) {
|
| - CaretBrowsing.escapeFromControl(document.activeElement);
|
| - sel = window.getSelection();
|
| - }
|
| -
|
| - if (sel.rangeCount == 0) {
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - if (CaretBrowsing.caretElement) {
|
| - CaretBrowsing.caretElement.style.visibility = 'visible';
|
| - CaretBrowsing.blinkFlag = true;
|
| - }
|
| -
|
| - var result = true;
|
| - switch (evt.keyCode) {
|
| - case 37:
|
| - result = CaretBrowsing.moveLeft(evt);
|
| - break;
|
| - case 38:
|
| - result = CaretBrowsing.moveUp(evt);
|
| - break;
|
| - case 39:
|
| - result = CaretBrowsing.moveRight(evt);
|
| - break;
|
| - case 40:
|
| - result = CaretBrowsing.moveDown(evt);
|
| - break;
|
| - }
|
| -
|
| - if (result == false) {
|
| - evt.preventDefault();
|
| - evt.stopPropagation();
|
| - }
|
| -
|
| - window.setTimeout(function() {
|
| - CaretBrowsing.updateCaretOrSelection(result == false);
|
| - }, 0);
|
| -
|
| - return result;
|
| -};
|
| -
|
| -/**
|
| - * Event handler, called when the mouse is clicked. Chrome already
|
| - * sets the selection when the mouse is clicked, all we need to do is
|
| - * update our cursor.
|
| - * @param {Event} evt The DOM event.
|
| - * @return {boolean} True if the default action should be performed.
|
| - */
|
| -CaretBrowsing.onClick = function(evt) {
|
| - if (!CaretBrowsing.isEnabled) {
|
| - return true;
|
| - }
|
| - window.setTimeout(function() {
|
| - CaretBrowsing.targetX = null;
|
| - CaretBrowsing.updateCaretOrSelection(false);
|
| - }, 0);
|
| - return true;
|
| -};
|
| -
|
| -/**
|
| - * Called at a regular interval. Blink the cursor by changing its visibility.
|
| - */
|
| -CaretBrowsing.caretBlinkFunction = function() {
|
| - if (CaretBrowsing.caretElement) {
|
| - if (CaretBrowsing.blinkFlag) {
|
| - CaretBrowsing.caretElement.style.backgroundColor =
|
| - CaretBrowsing.caretForeground;
|
| - CaretBrowsing.blinkFlag = false;
|
| - } else {
|
| - CaretBrowsing.caretElement.style.backgroundColor =
|
| - CaretBrowsing.caretBackground;
|
| - CaretBrowsing.blinkFlag = true;
|
| - }
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Update whether or not the caret is visible, based on whether caret browsing
|
| - * is enabled and whether this window / iframe has focus.
|
| - */
|
| -CaretBrowsing.updateIsCaretVisible = function() {
|
| - CaretBrowsing.isCaretVisible =
|
| - (CaretBrowsing.isEnabled && CaretBrowsing.isWindowFocused);
|
| - if (CaretBrowsing.isCaretVisible && !CaretBrowsing.caretElement) {
|
| - CaretBrowsing.setInitialCursor();
|
| - CaretBrowsing.updateCaretOrSelection(true);
|
| - if (CaretBrowsing.caretElement) {
|
| - CaretBrowsing.blinkFunctionId = window.setInterval(
|
| - CaretBrowsing.caretBlinkFunction, 500);
|
| - }
|
| - } else if (!CaretBrowsing.isCaretVisible &&
|
| - CaretBrowsing.caretElement) {
|
| - window.clearInterval(CaretBrowsing.blinkFunctionId);
|
| - if (CaretBrowsing.caretElement) {
|
| - CaretBrowsing.isSelectionCollapsed = false;
|
| - CaretBrowsing.caretElement.parentElement.removeChild(
|
| - CaretBrowsing.caretElement);
|
| - CaretBrowsing.caretElement = null;
|
| - }
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Called when the prefs get updated.
|
| - */
|
| -CaretBrowsing.onPrefsUpdated = function() {
|
| - chrome.storage.sync.get(null, function(result) {
|
| - if (!CaretBrowsing.forceEnabled) {
|
| - CaretBrowsing.isEnabled = result['enabled'];
|
| - }
|
| - CaretBrowsing.onEnable = result['onenable'];
|
| - CaretBrowsing.onJump = result['onjump'];
|
| - CaretBrowsing.recreateCaretElement();
|
| - });
|
| -};
|
| -
|
| -/**
|
| - * Called when this window / iframe gains focus.
|
| - */
|
| -CaretBrowsing.onWindowFocus = function() {
|
| - CaretBrowsing.isWindowFocused = true;
|
| - CaretBrowsing.updateIsCaretVisible();
|
| -};
|
| -
|
| -/**
|
| - * Called when this window / iframe loses focus.
|
| - */
|
| -CaretBrowsing.onWindowBlur = function() {
|
| - CaretBrowsing.isWindowFocused = false;
|
| - CaretBrowsing.updateIsCaretVisible();
|
| -};
|
| -
|
| -/**
|
| - * Initializes caret browsing by adding event listeners and extension
|
| - * message listeners.
|
| - */
|
| -CaretBrowsing.init = function() {
|
| - CaretBrowsing.isWindowFocused = document.hasFocus();
|
| -
|
| - document.addEventListener('keydown', CaretBrowsing.onKeyDown, false);
|
| - document.addEventListener('click', CaretBrowsing.onClick, false);
|
| - window.addEventListener('focus', CaretBrowsing.onWindowFocus, false);
|
| - window.addEventListener('blur', CaretBrowsing.onWindowBlur, false);
|
| -};
|
| -
|
| -window.setTimeout(function() {
|
| -
|
| - // Make sure the script only loads once.
|
| - if (!window['caretBrowsingLoaded']) {
|
| - window['caretBrowsingLoaded'] = true;
|
| - CaretBrowsing.init();
|
| -
|
| - if (document.body.getAttribute('caretbrowsing') == 'on') {
|
| - CaretBrowsing.forceEnabled = true;
|
| - CaretBrowsing.isEnabled = true;
|
| - CaretBrowsing.updateIsCaretVisible();
|
| - }
|
| -
|
| - chrome.storage.onChanged.addListener(function() {
|
| - CaretBrowsing.onPrefsUpdated();
|
| - });
|
| - CaretBrowsing.onPrefsUpdated();
|
| - }
|
| -
|
| -}, 0);
|
|
|