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

Unified Diff: ios/chrome/browser/find_in_page/resources/find_in_page.js

Issue 1023813003: [iOS] Upstream ios/chrome/browser/find_in_page (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@upstreamAutofill
Patch Set: Created 5 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ios/chrome/browser/find_in_page/js_findinpage_manager.mm ('k') | ios/chrome/ios_chrome.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ios/chrome/browser/find_in_page/resources/find_in_page.js
diff --git a/ios/chrome/browser/find_in_page/resources/find_in_page.js b/ios/chrome/browser/find_in_page/resources/find_in_page.js
new file mode 100644
index 0000000000000000000000000000000000000000..c1075824a5ac77237c54e9e345ffd54324d21e5f
--- /dev/null
+++ b/ios/chrome/browser/find_in_page/resources/find_in_page.js
@@ -0,0 +1,964 @@
+// Copyright 2012 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.
+
+/**
+ * This file is lifted from the GoogleMobile find tool.
+ *
+ * @fileoverview A find in page tool. It scans the DOM for elements with the
+ * text being search for, and wraps them with a span that highlights them.
+ *
+ * @author bmcmahan@google.com (Benjamin McMahan)
+ *
+ */
+
+/**
+ * Namespace for this file. Depends on __gCrWeb having already been injected.
+ */
+__gCrWeb['findInPage'] = {};
+
+/**
+ * Index of the current highlighted choice. -1 means none.
+ * @type {number}
+ */
+__gCrWeb['findInPage']['index'] = -1;
+
+/**
+ * The list of found searches in span form.
+ * @type {Array.<Element>}
+ */
+__gCrWeb['findInPage']['spans'] = [];
+
+/**
+ * The list of frame documents.
+ * TODO(justincohen): x-domain frames won't work.
+ * @type {Array.<Document>}
+ */
+__gCrWeb['findInPage'].frameDocs = [];
+
+/**
+ * Associate array to stash element styles while the element is highlighted.
+ * @type {Object.<Element,Object<string,string>>}
+ */
+__gCrWeb['findInPage'].savedElementStyles = {};
+
+/**
+ * The style DOM element that we add.
+ * @type {Element}
+ */
+__gCrWeb['findInPage'].style = null;
+
+/**
+ * Width we expect the page to be. For example (320/480) for iphone,
+ * (1024/768) for ipad.
+ * @type {number}
+ */
+__gCrWeb['findInPage'].pageWidth = 320;
+
+/**
+ * Height we expect the page to be.
+ * @type {number}
+ */
+__gCrWeb['findInPage'].pageHeight = 480;
+
+/**
+ * Maximum number of visible elements to count
+ * @type {number}
+ */
+__gCrWeb['findInPage'].maxVisibleElements = 100;
+
+/**
+ * A search is in progress.
+ * @type {boolean}
+ */
+__gCrWeb['findInPage'].searchInProgress = false;
+
+/**
+ * Node names that are not going to be processed.
+ * @type {Object}
+ */
+__gCrWeb['findInPage'].ignoreNodeNames = {
+ 'SCRIPT': 1,
+ 'STYLE': 1,
+ 'EMBED': 1,
+ 'OBJECT': 1
+};
+
+/**
+ * Class name of CSS element.
+ * @type {string}
+ */
+__gCrWeb['findInPage'].CSS_CLASS_NAME = 'find_in_page';
+
+/**
+ * ID of CSS style.
+ * @type {string}
+ */
+__gCrWeb['findInPage'].CSS_STYLE_ID = '__gCrWeb.findInPageStyle';
+
+/**
+ * Result passed back to app to indicate no results for the query.
+ * @type {string}
+ */
+__gCrWeb['findInPage'].NO_RESULTS = '[0,[0,0,0]]';
+
+/**
+ * Regex to escape regex special characters in a string.
+ * @type {RegExp}
+ */
+__gCrWeb['findInPage'].REGEX_ESCAPER = /([.?*+^$[\]\\(){}|-])/g;
+
+__gCrWeb['findInPage'].getCurrentSpan = function() {
+ return __gCrWeb['findInPage']['spans'][__gCrWeb['findInPage']['index']];
+};
+
+/**
+ * Creates the regex needed to find the text.
+ * @param {string} findText Phrase to look for.
+ * @param {boolean} opt_split True to split up the phrase.
+ * @return {RegExp} regex needed to find the text.
+ */
+__gCrWeb['findInPage'].getRegex = function(findText, opt_split) {
+ var regexString = '';
+ if (opt_split) {
+ var words = [];
+ var split = findText.split(' ');
+ for (var i = 0; i < split.length; i++) {
+ words.push(__gCrWeb['findInPage'].escapeRegex(split[i]));
+ }
+ var joinedWords = words.join('|');
+ regexString = '(' +
+ // Match at least one word.
+ '\\b(?:' + joinedWords + ')' +
+ // Include zero or more additional words separated by whitespace.
+ '(?:\\s*\\b(?:' + joinedWords + '))*' +
+ ')';
+ } else {
+ regexString = '(' + __gCrWeb['findInPage'].escapeRegex(findText) + ')';
+ }
+ return new RegExp(regexString, 'ig');
+};
+
+/**
+ * Get current timestamp.
+ * @return {number} timestamp.
+ */
+__gCrWeb['findInPage'].time = function() {
+ return (new Date).getTime();
+};
+
+/**
+ * After |timeCheck| iterations, return true if |now| - |start| is greater than
+ * |timeout|.
+ * @return {boolean} Find in page needs to return.
+ */
+__gCrWeb['findInPage'].overTime = function() {
+ return (__gCrWeb['findInPage'].time() - __gCrWeb['findInPage'].startTime >
+ __gCrWeb['findInPage'].timeout);
+};
+
+/**
+ * Looks for a phrase in the DOM.
+ * @param {string} findText Phrase to look for like "ben franklin".
+ * @param {boolean} opt_split True to split up the words and look for any
+ * of them. False to require the full phrase to be there.
+ * Undefined will try the full phrase, and if nothing is found do the split.
+ * @param {number} timeout Maximum time to run.
+ * @return {number} How many results there are in the page.
+ */
+__gCrWeb['findInPage']['highlightWord'] =
+ function(findText, opt_split, timeout) {
+ if (__gCrWeb['findInPage']['spans'] &&
+ __gCrWeb['findInPage']['spans'].length) {
+ // Clean up a previous run.
+ __gCrWeb['findInPage']['clearHighlight']();
+ }
+ if (!findText || !findText.replace(/\u00a0|\s/g, '')) {
+ // No searching for emptyness.
+ return __gCrWeb['findInPage'].NO_RESULTS;
+ }
+
+ // Store all DOM modifications to do them in a tight loop at once.
+ __gCrWeb['findInPage'].replacements = [];
+
+ // Node is what we are currently looking at.
+ __gCrWeb['findInPage'].node = document.body;
+
+ // Holds what nodes we have not processed yet.
+ __gCrWeb['findInPage'].stack = [];
+
+ // Push frames into stack too.
+ for (var i = __gCrWeb['findInPage'].frameDocs.length - 1; i >= 0; i--) {
+ var doc = __gCrWeb['findInPage'].frameDocs[i];
+ __gCrWeb['findInPage'].stack.push(doc);
+ }
+
+ // Number of visible elements found.
+ __gCrWeb['findInPage'].visibleFound = 0;
+
+ // Index tracking variables so search can be broken up into multiple calls.
+ __gCrWeb['findInPage'].visibleIndex = 0;
+ __gCrWeb['findInPage'].replacementsIndex = 0;
+ __gCrWeb['findInPage'].replacementNewNodesIndex = 0;
+
+ __gCrWeb['findInPage'].regex =
+ __gCrWeb['findInPage'].getRegex(findText, opt_split);
+
+ __gCrWeb['findInPage'].searchInProgress = true;
+
+ return __gCrWeb['findInPage']['pumpSearch'](timeout);
+};
+
+/**
+ * Break up find in page DOM regex, DOM manipulation and visibility check
+ * into sections that can be stopped and restarted later. Because the js runs
+ * in the main UI thread, anything over timeout will cause the UI to lock up.
+ * @param {number} timeout Only run find in page until timeout.
+ * @return {boolean} Whether find in page completed.
+ */
+__gCrWeb['findInPage']['pumpSearch'] = function(timeout) {
+ var opt_split = false;
+ // TODO(justincohen): It would be better if this DCHECKed.
+ if (__gCrWeb['findInPage'].searchInProgress == false)
+ return __gCrWeb['findInPage'].NO_RESULTS;
+
+ __gCrWeb['findInPage'].timeout = timeout;
+ __gCrWeb['findInPage'].startTime = __gCrWeb['findInPage'].time();
+
+ var regex = __gCrWeb['findInPage'].regex;
+ // Go through every node in DFS fashion.
+ while (__gCrWeb['findInPage'].node) {
+ var node = __gCrWeb['findInPage'].node;
+ var children = node.childNodes;
+ if (children && children.length) {
+ // add all (reasonable) children
+ for (var i = children.length - 1; i >= 0; --i) {
+ var child = children[i];
+ if ((child.nodeType == 1 || child.nodeType == 3) &&
+ !__gCrWeb['findInPage'].ignoreNodeNames[child.nodeName]) {
+ __gCrWeb['findInPage'].stack.push(children[i]);
+ }
+ }
+ }
+ if (node.nodeType == 3 && node.parentNode) {
+ var strIndex = 0;
+ var nodes = [];
+ var match;
+ while (match = regex.exec(node.textContent)) {
+ try {
+ var matchText = match[0];
+
+ // If there is content before this match, add it to a new text node.
+ if (match.index > 0) {
+ var nodeSubstr = node.textContent.substring(strIndex,
+ match.index);
+ nodes.push(node.ownerDocument.createTextNode(nodeSubstr));
+ }
+
+ // Now create our matched element.
+ var element = node.ownerDocument.createElement('chrome_find');
+ element.setAttribute('class', __gCrWeb['findInPage'].CSS_CLASS_NAME);
+ element.innerHTML = __gCrWeb['findInPage'].escapeHTML(matchText);
+ nodes.push(element);
+
+ strIndex = match.index + matchText.length;
+ } catch (e) {
+ // Do nothing.
+ }
+ }
+ if (nodes.length) {
+ // Add any text after our matches to a new text node.
+ if (strIndex < node.textContent.length) {
+ var substr = node.textContent.substring(strIndex,
+ node.textContent.length);
+ nodes.push(node.ownerDocument.createTextNode(substr));
+ }
+ __gCrWeb['findInPage'].replacements.push(
+ {oldNode: node, newNodes: nodes});
+ regex.lastIndex = 0;
+ }
+
+ }
+
+ if (__gCrWeb['findInPage'].overTime())
+ return '[false]';
+
+ if (__gCrWeb['findInPage'].stack.length > 0) {
+ __gCrWeb['findInPage'].node = __gCrWeb['findInPage'].stack.pop();
+ } else {
+ __gCrWeb['findInPage'].node = null;
+ }
+ }
+
+ // Insert each of the replacement nodes into the old node's parent, then
+ // remove the old node.
+ var replacements = __gCrWeb['findInPage'].replacements;
+
+ // Last position in replacements array.
+ var rIndex = __gCrWeb['findInPage'].replacementsIndex;
+ var rMax = replacements.length;
+ for (; rIndex < rMax; rIndex++) {
+ var replacement = replacements[rIndex];
+ var parent = replacement.oldNode.parentNode;
+ if (parent == null)
+ continue;
+ var rNodesMax = replacement.newNodes.length;
+ for (var rNodesIndex = __gCrWeb['findInPage'].replacementNewNodesIndex;
+ rNodesIndex < rNodesMax; rNodesIndex++) {
+ if (__gCrWeb['findInPage'].overTime()) {
+ __gCrWeb['findInPage'].replacementsIndex = rIndex;
+ __gCrWeb['findInPage'].replacementNewNodesIndex = rNodesIndex;
+ return __gCrWeb.stringify([false]);
+ }
+ parent.insertBefore(replacement.newNodes[rNodesIndex],
+ replacement.oldNode);
+ }
+ parent.removeChild(replacement.oldNode);
+ __gCrWeb['findInPage'].replacementNewNodesIndex = 0;
+ }
+ // Save last position in replacements array.
+ __gCrWeb['findInPage'].replacementsIndex = rIndex;
+
+ __gCrWeb['findInPage']['spans'] =
+ __gCrWeb['findInPage'].getAllElementsByClassName(
+ __gCrWeb['findInPage'].CSS_CLASS_NAME);
+
+ // Count visible elements.
+ var max = __gCrWeb['findInPage']['spans'].length;
+ var maxVisible = __gCrWeb['findInPage'].maxVisibleElements;
+ for (var index = __gCrWeb['findInPage'].visibleIndex; index < max; index++) {
+ var elem = __gCrWeb['findInPage']['spans'][index];
+ if (__gCrWeb['findInPage'].overTime()) {
+ __gCrWeb['findInPage'].visibleIndex = index;
+ return __gCrWeb.stringify([false]);
+ }
+
+ // Stop after |maxVisible| elements.
+ if (__gCrWeb['findInPage'].visibleFound > maxVisible) {
+ __gCrWeb['findInPage']['spans'][index].visibleIndex = maxVisible;
+ continue;
+ }
+
+ if (__gCrWeb['findInPage'].isVisible(elem)) {
+ __gCrWeb['findInPage'].visibleFound++;
+ __gCrWeb['findInPage']['spans'][index].visibleIndex =
+ __gCrWeb['findInPage'].visibleFound;
+ }
+ }
+
+ __gCrWeb['findInPage'].searchInProgress = false;
+
+ var pos;
+ // Try again flow.
+ // If opt_split is true, we are done since we won't do any better.
+ // If opt_split is false, they were explicit about wanting the full thing
+ // so do not try with a split.
+ // If opt_split is undefined and we did not find an answer, go ahead and try
+ // splitting the terms.
+ if (__gCrWeb['findInPage']['spans'].length == 0 && opt_split === undefined) {
+ // Try to be more aggressive:
+ return __gCrWeb['findInPage']['highlightWord'](findText, true);
+ } else {
+ pos = __gCrWeb['findInPage']['goNext']();
+ if (pos) {
+ return '[' + __gCrWeb['findInPage'].visibleFound + ',' + pos + ']';
+ } else if (opt_split === undefined) {
+ // Nothing visible, go ahead and be more aggressive.
+ return __gCrWeb['findInPage']['highlightWord'](findText, true);
+ } else {
+ return __gCrWeb['findInPage'].NO_RESULTS;
+ }
+ }
+};
+
+/**
+ * Converts a node list to an array.
+ * @param {object} nodeList DOM node list.
+ * @return {object} array.
+ */
+__gCrWeb['findInPage'].toArray = function(nodeList) {
+ var array = [];
+ for (var i = 0; i < nodeList.length; i++)
+ array[i] = nodeList[i];
+ return array;
+};
+
+/**
+ * Return all elements of class name, spread out over various frames.
+ * @param {string} name of class.
+ * @return {object} array of elements matching class name.
+ */
+__gCrWeb['findInPage'].getAllElementsByClassName = function(name) {
+ var nodeList = document.getElementsByClassName(name);
+ var elements = __gCrWeb['findInPage'].toArray(nodeList);
+ for (var i = __gCrWeb['findInPage'].frameDocs.length - 1; i >= 0; i--) {
+ var doc = __gCrWeb['findInPage'].frameDocs[i];
+ nodeList = doc.getElementsByClassName(name);
+ elements = elements.concat(__gCrWeb['findInPage'].toArray(nodeList));
+ }
+ return elements;
+};
+
+/**
+ * Removes all currently highlighted spans.
+ * Note: It does not restore previous state, just removes the class name.
+ */
+__gCrWeb['findInPage']['clearHighlight'] = function() {
+ if (__gCrWeb['findInPage']['index'] >= 0) {
+ __gCrWeb['findInPage'].removeSelectHighlight(
+ __gCrWeb['findInPage'].getCurrentSpan());
+ }
+ // Store all DOM modifications to do them in a tight loop.
+ var modifications = [];
+ var length = __gCrWeb['findInPage']['spans'].length;
+ var prevParent = null;
+ for (var i = length - 1; i >= 0; i--) {
+ var elem = __gCrWeb['findInPage']['spans'][i];
+ var parentNode = elem.parentNode;
+ // Safari has an occasional |elem.innerText| bug that drops the trailing
+ // space. |elem.innerText| would be more correct in this situation, but
+ // since we only allow text in this element, grabbing the HTML value should
+ // not matter.
+ var nodeText = elem.innerHTML;
+ // If this element has the same parent as the previous, check if we should
+ // add this node to the previous one.
+ if (prevParent && prevParent.isSameNode(parentNode) &&
+ elem.nextSibling.isSameNode(
+ __gCrWeb['findInPage']['spans'][i + 1].previousSibling)) {
+ var prevMod = modifications[modifications.length - 1];
+ prevMod.nodesToRemove.push(elem);
+ var elemText = elem.innerText;
+ if (elem.previousSibling) {
+ prevMod.nodesToRemove.push(elem.previousSibling);
+ elemText = elem.previousSibling.textContent + elemText;
+ }
+ prevMod.replacement.textContent =
+ elemText + prevMod.replacement.textContent;
+ }
+ else { // Element isn't attached to previous, so create a new modification.
+ var nodesToRemove = [elem];
+ if (elem.previousSibling && elem.previousSibling.nodeType == 3) {
+ nodesToRemove.push(elem.previousSibling);
+ nodeText = elem.previousSibling.textContent + nodeText;
+ }
+ if (elem.nextSibling && elem.nextSibling.nodeType == 3) {
+ nodesToRemove.push(elem.nextSibling);
+ nodeText = nodeText + elem.nextSibling.textContent;
+ }
+ var textNode = elem.ownerDocument.createTextNode(nodeText);
+ modifications.push({nodesToRemove: nodesToRemove, replacement: textNode});
+ }
+ prevParent = parentNode;
+ }
+ var numMods = modifications.length;
+ for (i = numMods - 1; i >= 0; i--) {
+ var mod = modifications[i];
+ for (var j = 0; j < mod.nodesToRemove.length; j++) {
+ var existing = mod.nodesToRemove[j];
+ if (j == 0) {
+ existing.parentNode.replaceChild(mod.replacement, existing);
+ } else {
+ existing.parentNode.removeChild(existing);
+ }
+ }
+ }
+
+ __gCrWeb['findInPage']['spans'] = [];
+ __gCrWeb['findInPage']['index'] = -1;
+};
+
+/**
+ * Increments the index of the current highlighted span or, if the index is
+ * already at the end, sets it to the index of the first span in the page.
+ */
+__gCrWeb['findInPage']['incrementIndex'] = function() {
+ if (__gCrWeb['findInPage']['index'] >=
+ __gCrWeb['findInPage']['spans'].length - 1) {
+ __gCrWeb['findInPage']['index'] = 0;
+ } else {
+ __gCrWeb['findInPage']['index']++;
+ }
+};
+
+/**
+ * Switches to the next result, animating a little highlight in the process.
+ * @return {string} JSON encoded array of coordinates to scroll to, or blank if
+ * nothing happened.
+ */
+__gCrWeb['findInPage']['goNext'] = function() {
+ if (!__gCrWeb['findInPage']['spans'] ||
+ __gCrWeb['findInPage']['spans'].length == 0) {
+ return '';
+ }
+ if (__gCrWeb['findInPage']['index'] >= 0) {
+ // Remove previous highlight.
+ __gCrWeb['findInPage'].removeSelectHighlight(
+ __gCrWeb['findInPage'].getCurrentSpan());
+ }
+ // Iterate through to the next index, but because they might not be visible,
+ // keep trying until you find one that is. Make sure we don't loop forever by
+ // stopping on what we are currently highlighting.
+ var oldIndex = __gCrWeb['findInPage']['index'];
+ __gCrWeb['findInPage']['incrementIndex']();
+ while (!__gCrWeb['findInPage'].isVisible(
+ __gCrWeb['findInPage'].getCurrentSpan())) {
+ if (oldIndex === __gCrWeb['findInPage']['index']) {
+ // Checked all spans but didn't find anything else visible.
+ return '';
+ }
+ __gCrWeb['findInPage']['incrementIndex']();
+ if (0 === __gCrWeb['findInPage']['index'] && oldIndex < 0) {
+ // Didn't find anything visible and haven't highlighted anything yet.
+ return '';
+ }
+ }
+ // Return scroll dimensions.
+ return __gCrWeb['findInPage'].findScrollDimensions();
+};
+
+/**
+ * Decrements the index of the current highlighted span or, if the index is
+ * already at the beginning, sets it to the index of the last span in the page.
+ */
+__gCrWeb['findInPage']['decrementIndex'] = function() {
+ if (__gCrWeb['findInPage']['index'] <= 0) {
+ __gCrWeb['findInPage']['index'] =
+ __gCrWeb['findInPage']['spans'].length - 1;
+ } else {
+ __gCrWeb['findInPage']['index']--;
+ }
+};
+
+/**
+ * Switches to the previous result, animating a little highlight in the process.
+ * @return {string} JSON encoded array of coordinates to scroll to, or blank if
+ * nothing happened.
+ */
+__gCrWeb['findInPage']['goPrev'] = function() {
+ if (!__gCrWeb['findInPage']['spans'] ||
+ __gCrWeb['findInPage']['spans'].length == 0) {
+ return '';
+ }
+ if (__gCrWeb['findInPage']['index'] >= 0) {
+ // Remove previous highlight.
+ __gCrWeb['findInPage'].removeSelectHighlight(
+ __gCrWeb['findInPage'].getCurrentSpan());
+ }
+ // Iterate through to the next index, but because they might not be visible,
+ // keep trying until you find one that is. Make sure we don't loop forever by
+ // stopping on what we are currently highlighting.
+ var old = __gCrWeb['findInPage']['index'];
+ __gCrWeb['findInPage']['decrementIndex']();
+ while (!__gCrWeb['findInPage'].isVisible(
+ __gCrWeb['findInPage'].getCurrentSpan())) {
+ __gCrWeb['findInPage']['decrementIndex']();
+ if (old == __gCrWeb['findInPage']['index']) {
+ // Checked all spans but didn't find anything.
+ return '';
+ }
+ }
+
+ // Return scroll dimensions.
+ return __gCrWeb['findInPage'].findScrollDimensions();
+};
+
+/**
+ * Adds the special highlighting to the result at the index.
+ * @param {number} opt_index Index to replace __gCrWeb['findInPage']['index']
+ * with.
+ */
+__gCrWeb['findInPage'].addHighlightToIndex = function(opt_index) {
+ if (opt_index !== undefined) {
+ __gCrWeb['findInPage']['index'] = opt_index;
+ }
+ __gCrWeb['findInPage'].addSelectHighlight(
+ __gCrWeb['findInPage'].getCurrentSpan());
+};
+
+/**
+ * Updates the elements style, while saving the old style in
+ * __gCrWeb['findInPage'].savedElementStyles.
+ * @param {Element} element Element to update.
+ * @param {string} style Name of the style to update.
+ * @param {string} value New style value.
+ */
+__gCrWeb['findInPage'].updateElementStyle = function(element, style, value) {
+ if (!__gCrWeb['findInPage'].savedElementStyles[element]) {
+ __gCrWeb['findInPage'].savedElementStyles[element] = {};
+ }
+ // We need to keep the original style setting for this element, so if we've
+ // already saved a value for this style don't update it.
+ if (!__gCrWeb['findInPage'].savedElementStyles[element][style]) {
+ __gCrWeb['findInPage'].savedElementStyles[element][style] =
+ element.style[style];
+ }
+ element.style[style] = value;
+};
+
+/**
+ * Adds selected highlight style to the specified element.
+ * @param {Element} element Element to highlight.
+ */
+__gCrWeb['findInPage'].addSelectHighlight = function(element) {
+ element.className = (element.className || '') + ' findysel';
+};
+
+/**
+ * Removes selected highlight style from the specified element.
+ * @param {Element} element Element to remove highlighting from.
+ */
+__gCrWeb['findInPage'].removeSelectHighlight = function(element) {
+ element.className = (element.className || '').replace(/\sfindysel/g, '');
+
+ // Restore any styles we may have saved when adding the select highlighting.
+ var savedStyles = __gCrWeb['findInPage'].savedElementStyles[element];
+ if (savedStyles) {
+ for (var style in savedStyles) {
+ element.style[style] = savedStyles[style];
+ }
+ delete __gCrWeb['findInPage'].savedElementStyles[element];
+ }
+};
+
+/**
+ * Normalize coordinates according to the current document dimensions. Don't go
+ * too far off the screen in either direction. Try to center if possible.
+ * @param {Element} elem Element to find normalized coordinates for.
+ * @return {Array.<number>} Normalized coordinates.
+ */
+__gCrWeb['findInPage'].getNormalizedCoordinates = function(elem) {
+ var fip = __gCrWeb['findInPage'];
+ var pos = fip.findAbsolutePosition(elem);
+ var maxX =
+ Math.max(fip.getBodyWidth(), pos[0] + elem.offsetWidth);
+ var maxY =
+ Math.max(fip.getBodyHeight(), pos[1] + elem.offsetHeight);
+ // Don't go too far off the screen in either direction. Try to center if
+ // possible.
+ var xPos = Math.max(0,
+ Math.min(maxX - window.innerWidth,
+ pos[0] - (window.innerWidth / 2)));
+ var yPos = Math.max(0,
+ Math.min(maxY - window.innerHeight,
+ pos[1] - (window.innerHeight / 2)));
+ return [xPos, yPos];
+};
+
+/**
+ * Scale coordinates according to the width of the screen, in case the screen
+ * is zoomed out.
+ * @param {Array.<number>} coordinates Coordinates to scale.
+ * @return {Array.<number>} Scaled coordinates.
+ */
+__gCrWeb['findInPage'].scaleCoordinates = function(coordinates) {
+ var scaleFactor = __gCrWeb['findInPage'].pageWidth / window.innerWidth;
+ return [coordinates[0] * scaleFactor, coordinates[1] * scaleFactor];
+};
+
+/**
+ * Finds the position of the result and scrolls to it.
+ * @param {number} opt_index Index to replace __gCrWeb['findInPage']['index']
+ * with.
+ * @return {string} JSON encoded array of the scroll coordinates "[x, y]".
+ */
+__gCrWeb['findInPage'].findScrollDimensions = function(opt_index) {
+ if (opt_index !== undefined) {
+ __gCrWeb['findInPage']['index'] = opt_index;
+ }
+ var elem = __gCrWeb['findInPage'].getCurrentSpan();
+ if (!elem) {
+ return '';
+ }
+ var normalized = __gCrWeb['findInPage'].getNormalizedCoordinates(elem);
+ var xPos = normalized[0];
+ var yPos = normalized[1];
+
+ // Perform the scroll.
+ //window.scrollTo(xPos, yPos);
+
+ if (xPos < window.pageXOffset ||
+ xPos >= (window.pageXOffset + window.innerWidth) ||
+ yPos < window.pageYOffset ||
+ yPos >= (window.pageYOffset + window.innerHeight)) {
+ // If it's off the screen. Wait a bit to start the highlight animation so
+ // that scrolling can get there first.
+ window.setTimeout(__gCrWeb['findInPage'].addHighlightToIndex, 250);
+ } else {
+ __gCrWeb['findInPage'].addHighlightToIndex();
+ }
+ var scaled = __gCrWeb['findInPage'].scaleCoordinates(normalized);
+ var index = __gCrWeb['findInPage'].getCurrentSpan().visibleIndex;
+ scaled.unshift(index);
+ return __gCrWeb.stringify(scaled);
+};
+
+/**
+ * Initialize the __gCrWeb['findInPage'] module.
+ * @param {number} width Width of page.
+ * @param {number} height Height of page.
+
+ */
+__gCrWeb['findInPage']['init'] = function(width, height) {
+ if (__gCrWeb['findInPage'].hasInitialized) {
+ return;
+ }
+ __gCrWeb['findInPage'].pageWidth = width;
+ __gCrWeb['findInPage'].pageHeight = height;
+ __gCrWeb['findInPage'].frameDocs = __gCrWeb['findInPage'].frameDocuments();
+ __gCrWeb['findInPage'].enable();
+ __gCrWeb['findInPage'].hasInitialized = true;
+};
+
+/**
+ * When the GSA app detects a zoom change, we need to update our css.
+ * @param {number} width Width of page.
+ * @param {number} height Height of page.
+ */
+__gCrWeb['findInPage']['fixZoom'] = function(width, height) {
+ __gCrWeb['findInPage'].pageWidth = width;
+ __gCrWeb['findInPage'].pageHeight = height;
+ if (__gCrWeb['findInPage'].style) {
+ __gCrWeb['findInPage'].removeStyle();
+ __gCrWeb['findInPage'].addStyle();
+ }
+};
+
+/**
+ * Enable the __gCrWeb['findInPage'] module.
+ * Mainly just adds the style for the classes.
+ */
+__gCrWeb['findInPage'].enable = function() {
+ if (__gCrWeb['findInPage'].style) {
+ // Already enabled.
+ return;
+ }
+ __gCrWeb['findInPage'].addStyle();
+};
+
+/**
+ * Gets the scale ratio between the application window and the web document.
+ * @return {number} Scale.
+ */
+__gCrWeb['findInPage'].getPageScale = function() {
+ return (__gCrWeb['findInPage'].pageWidth /
+ __gCrWeb['findInPage'].getBodyWidth());
+};
+
+/**
+ * Maximum padding added to a highlighted item when selected.
+ * @type {number}
+ */
+__gCrWeb['findInPage'].MAX_HIGHLIGHT_PADDING = 10;
+
+/**
+ * Adds the appropriate style element to the page.
+ */
+__gCrWeb['findInPage'].addStyle = function() {
+ __gCrWeb['findInPage'].addDocumentStyle(document);
+ for (var i = __gCrWeb['findInPage'].frameDocs.length - 1; i >= 0; i--) {
+ var doc = __gCrWeb['findInPage'].frameDocs[i];
+ __gCrWeb['findInPage'].addDocumentStyle(doc);
+ }
+};
+
+__gCrWeb['findInPage'].addDocumentStyle = function(thisDocument) {
+ var styleContent = [];
+ function addCSSRule(name, style) {
+ styleContent.push(name, '{', style, '}');
+ };
+ var scale = __gCrWeb['findInPage'].getPageScale();
+ var zoom = (1.0 / scale);
+ var left = ((1 - scale) / 2 * 100);
+ addCSSRule('.' + __gCrWeb['findInPage'].CSS_CLASS_NAME,
+ 'background-color:#ffff00 !important;' +
+ 'padding:0px;margin:0px;' +
+ 'overflow:visible !important;');
+ addCSSRule('.findysel',
+ 'background-color:#ff9632 !important;' +
+ 'padding:0px;margin:0px;' +
+ 'overflow:visible !important;');
+ __gCrWeb['findInPage'].style = thisDocument.createElement('style');
+ __gCrWeb['findInPage'].style.id = __gCrWeb['findInPage'].CSS_STYLE_ID;
+ __gCrWeb['findInPage'].style.setAttribute('type', 'text/css');
+ __gCrWeb['findInPage'].style.appendChild(
+ thisDocument.createTextNode(styleContent.join('')));
+ thisDocument.body.appendChild(__gCrWeb['findInPage'].style);
+};
+
+/**
+ * Removes the style element from the page.
+ */
+__gCrWeb['findInPage'].removeStyle = function() {
+ if (__gCrWeb['findInPage'].style) {
+ __gCrWeb['findInPage'].removeDocumentStyle(document);
+ for (var i = __gCrWeb['findInPage'].frameDocs.length - 1; i >= 0; i--) {
+ var doc = __gCrWeb['findInPage'].frameDocs[i];
+ __gCrWeb['findInPage'].removeDocumentStyle(doc);
+ }
+ __gCrWeb['findInPage'].style = null;
+ }
+};
+
+__gCrWeb['findInPage'].removeDocumentStyle = function(thisDocument) {
+ var style = thisDocument.getElementById(__gCrWeb['findInPage'].CSS_STYLE_ID);
+ thisDocument.body.removeChild(style);
+};
+
+/**
+ * Disables the __gCrWeb['findInPage'] module.
+ * Basically just removes the style and class names.
+ */
+__gCrWeb['findInPage']['disable'] = function() {
+ if (__gCrWeb['findInPage'].style) {
+ __gCrWeb['findInPage'].removeStyle();
+ window.setTimeout(__gCrWeb['findInPage']['clearHighlight'], 0);
+ }
+ __gCrWeb['findInPage'].hasInitialized = false;
+};
+
+/**
+* Returns the width of the document.body. Sometimes though the body lies to
+* try to make the page not break rails, so attempt to find those as well.
+* An example: wikipedia pages for the ipad.
+* @return {number} Width of the document body.
+*/
+__gCrWeb['findInPage'].getBodyWidth = function() {
+ var body = document.body;
+ var documentElement = document.documentElement;
+ return Math.max(body.scrollWidth, documentElement.scrollWidth,
+ body.offsetWidth, documentElement.offsetWidth,
+ body.clientWidth, documentElement.clientWidth);
+};
+
+/**
+ * Returns the height of the document.body. Sometimes though the body lies to
+ * try to make the page not break rails, so attempt to find those as well.
+ * An example: wikipedia pages for the ipad.
+ * @return {number} Height of the document body.
+ */
+__gCrWeb['findInPage'].getBodyHeight = function() {
+ var body = document.body;
+ var documentElement = document.documentElement;
+ return Math.max(body.scrollHeight, documentElement.scrollHeight,
+ body.offsetHeight, documentElement.offsetHeight,
+ body.clientHeight, documentElement.clientHeight);
+};
+
+/**
+ * Helper function that determines if an element is visible.
+ * @param {Element} elem Element to check.
+ * @return {boolean} Whether elem is visible or not.
+ */
+__gCrWeb['findInPage'].isVisible = function(elem) {
+ if (!elem) {
+ return false;
+ }
+ var top = 0;
+ var left = 0;
+ var bottom = Infinity;
+ var right = Infinity;
+
+ var originalElement = elem;
+ var nextOffsetParent = originalElement.offsetParent;
+ var computedStyle =
+ elem.ownerDocument.defaultView.getComputedStyle(elem, null);
+
+ // We are currently handling all scrolling through the app, which means we can
+ // only scroll the window, not any scrollable containers in the DOM itself. So
+ // for now this function returns false if the element is scrolled outside the
+ // viewable area of its ancestors.
+ // TODO (jonwall): handle scrolling within the DOM.
+ var pageHeight = __gCrWeb['findInPage'].getBodyHeight();
+ var pageWidth = __gCrWeb['findInPage'].getBodyWidth();
+
+ while (elem && elem.nodeName != 'BODY') {
+ if (elem.style.display === 'none' ||
+ elem.style.visibility === 'hidden' ||
+ elem.style.opacity === 0 ||
+ computedStyle.display === 'none' ||
+ computedStyle.visibility === 'hidden' ||
+ computedStyle.opacity === 0) {
+ return false;
+ }
+
+ // For the original element and all ancestor offsetParents, trim down the
+ // visible area of the original element.
+ if (elem.isSameNode(originalElement) || elem.isSameNode(nextOffsetParent)) {
+ var visible = elem.getBoundingClientRect();
+ if (elem.style.overflow === 'hidden' &&
+ (visible.width === 0 || visible.height === 0))
+ return false;
+
+ top = Math.max(top, visible.top + window.pageYOffset);
+ bottom = Math.min(bottom, visible.bottom + window.pageYOffset);
+ left = Math.max(left, visible.left + window.pageXOffset);
+ right = Math.min(right, visible.right + window.pageXOffset);
+
+ // The element is not within the original viewport.
+ var notWithinViewport = top < 0 || left < 0;
+
+ // The element is flowing off the boundary of the page. Note this is
+ // not comparing to the size of the window, but the calculated offset
+ // size of the document body. This can happen if the element is within
+ // a scrollable container in the page.
+ var offPage = right > pageWidth || bottom > pageHeight;
+ if (notWithinViewport || offPage) {
+ return false;
+ }
+ nextOffsetParent = elem.offsetParent;
+ }
+
+ elem = elem.parentNode;
+ computedStyle = elem.ownerDocument.defaultView.getComputedStyle(elem, null);
+ }
+ return true;
+};
+
+/**
+ * Helper function to find the absolute position of an element on the page.
+ * @param {Element} elem Element to check.
+ * @return {Array.<number>} [x, y] positions.
+ */
+__gCrWeb['findInPage'].findAbsolutePosition = function(elem) {
+ var boundingRect = elem.getBoundingClientRect();
+ return [boundingRect.left + window.pageXOffset,
+ boundingRect.top + window.pageYOffset];
+};
+
+/**
+ * @param {string} text Text to escape.
+ * @return {string} escaped text.
+ */
+__gCrWeb['findInPage'].escapeHTML = function(text) {
+ var unusedDiv = document.createElement('div');
+ unusedDiv.innerText = text;
+ return unusedDiv.innerHTML;
+};
+
+/**
+ * Escapes regexp special characters.
+ * @param {string} text Text to escape.
+ * @return {string} escaped text.
+ */
+__gCrWeb['findInPage'].escapeRegex = function(text) {
+ return text.replace(__gCrWeb['findInPage'].REGEX_ESCAPER, '\\$1');
+};
+
+/**
+ * Gather all iframes in the main window.
+ * @return {Array.<Document>} frames.
+ */
+__gCrWeb['findInPage'].frameDocuments = function() {
+ var windowsToSearch = [window];
+ var documents = [];
+ while (windowsToSearch.length != 0) {
+ var win = windowsToSearch.pop();
+ for (var i = win.frames.length - 1; i >= 0; i--) {
+ if (win.frames[i].document) {
+ documents.push(win.frames[i].document);
+ windowsToSearch.push(win.frames[i]);
+ }
+ }
+ }
+ return documents;
+};
« no previous file with comments | « ios/chrome/browser/find_in_page/js_findinpage_manager.mm ('k') | ios/chrome/ios_chrome.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698