summaryrefslogtreecommitdiff
path: root/mobile/android/chrome/content/FindHelper.js
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/chrome/content/FindHelper.js')
-rw-r--r--mobile/android/chrome/content/FindHelper.js197
1 files changed, 197 insertions, 0 deletions
diff --git a/mobile/android/chrome/content/FindHelper.js b/mobile/android/chrome/content/FindHelper.js
new file mode 100644
index 0000000000..037b182d64
--- /dev/null
+++ b/mobile/android/chrome/content/FindHelper.js
@@ -0,0 +1,197 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var FindHelper = {
+ _finder: null,
+ _targetTab: null,
+ _initialViewport: null,
+ _viewportChanged: false,
+ _result: null,
+
+ // Start of nsIObserver implementation.
+
+ observe: function(aMessage, aTopic, aData) {
+ switch(aTopic) {
+ case "FindInPage:Opened": {
+ this._findOpened();
+ break;
+ }
+
+ case "Tab:Selected": {
+ // Allow for page switching.
+ this._uninit();
+ break;
+ }
+
+ case "FindInPage:Closed":
+ this._uninit();
+ this._findClosed();
+ break;
+ }
+ },
+
+ /**
+ * When the FindInPageBar opens/ becomes visible, it's time to:
+ * 1. Add listeners for other message types sent from the FindInPageBar
+ * 2. initialize the Finder instance, if necessary.
+ */
+ _findOpened: function() {
+ Messaging.addListener(data => this.doFind(data), "FindInPage:Find");
+ Messaging.addListener(data => this.findAgain(data, false), "FindInPage:Next");
+ Messaging.addListener(data => this.findAgain(data, true), "FindInPage:Prev");
+
+ // Initialize the finder component for the current page by performing a fake find.
+ this._init();
+ this._finder.requestMatchesCount("");
+ },
+
+ /**
+ * Fetch the Finder instance from the active tabs' browser and start tracking
+ * the active viewport.
+ */
+ _init: function() {
+ // If there's no find in progress, start one.
+ if (this._finder) {
+ return;
+ }
+
+ this._targetTab = BrowserApp.selectedTab;
+ try {
+ this._finder = this._targetTab.browser.finder;
+ } catch (e) {
+ throw new Error("FindHelper: " + e + "\n" +
+ "JS stack: \n" + (e.stack || Components.stack.formattedStack));
+ }
+
+ this._finder.addResultListener(this);
+ this._initialViewport = JSON.stringify(this._targetTab.getViewport());
+ this._viewportChanged = false;
+ },
+
+ /**
+ * Detach from the Finder instance (so stop listening for messages) and stop
+ * tracking the active viewport.
+ */
+ _uninit: function() {
+ // If there's no find in progress, there's nothing to clean up.
+ if (!this._finder) {
+ return;
+ }
+
+ this._finder.removeSelection();
+ this._finder.removeResultListener(this);
+ this._finder = null;
+ this._targetTab = null;
+ this._initialViewport = null;
+ this._viewportChanged = false;
+ },
+
+ /**
+ * When the FindInPageBar closes, it's time to stop listening for its messages.
+ */
+ _findClosed: function() {
+ Messaging.removeListener("FindInPage:Find");
+ Messaging.removeListener("FindInPage:Next");
+ Messaging.removeListener("FindInPage:Prev");
+ },
+
+ /**
+ * Start an asynchronous find-in-page operation, using the current Finder
+ * instance and request to count the amount of matches.
+ * If no Finder instance is currently active, we'll lazily initialize it here.
+ *
+ * @param {String} searchString Word to search for in the current document
+ * @return {Object} Echo of the current find action
+ */
+ doFind: function(searchString) {
+ if (!this._finder) {
+ this._init();
+ }
+
+ this._finder.fastFind(searchString, false);
+ return { searchString, findBackwards: false };
+ },
+
+ /**
+ * Restart the same find-in-page operation as before via `doFind()`. If we
+ * haven't called `doFind()`, we simply kick off a regular find.
+ *
+ * @param {String} searchString Word to search for in the current document
+ * @param {Boolean} findBackwards Direction to search in
+ * @return {Object} Echo of the current find action
+ */
+ findAgain: function(searchString, findBackwards) {
+ // This always happens if the user taps next/previous after re-opening the
+ // search bar, and not only forces _init() but also an initial fastFind(STRING)
+ // before any findAgain(DIRECTION).
+ if (!this._finder) {
+ return this.doFind(searchString);
+ }
+
+ this._finder.findAgain(findBackwards, false, false);
+ return { searchString, findBackwards };
+ },
+
+ // Start of Finder.jsm listener implementation.
+
+ /**
+ * Pass along the count results to FindInPageBar for display. The result that
+ * is sent to the FindInPageBar is augmented with the current find-in-page count
+ * limit.
+ *
+ * @param {Object} result Result coming from the Finder instance that contains
+ * the following properties:
+ * - {Number} total The total amount of matches found
+ * - {Number} current The index of current found range
+ * in the document
+ */
+ onMatchesCountResult: function(result) {
+ this._result = result;
+
+ Messaging.sendRequest(Object.assign({
+ type: "FindInPage:MatchesCountResult"
+ }, this._result));
+ },
+
+ /**
+ * When a find-in-page action finishes, this method is invoked. This is mainly
+ * used at the moment to detect if the current viewport has changed, which might
+ * be indicated by not finding a string in the current page.
+ *
+ * @param {Object} aData A dictionary, representing the find result, which
+ * contains the following properties:
+ * - {String} searchString Word that was searched for
+ * in the current document
+ * - {Number} result One of the following
+ * Ci.nsITypeAheadFind.* result
+ * indicators: FIND_FOUND,
+ * FIND_NOTFOUND, FIND_WRAPPED,
+ * FIND_PENDING
+ * - {Boolean} findBackwards Whether the search direction
+ * was backwards
+ * - {Boolean} findAgain Whether the previous search
+ * was repeated
+ * - {Boolean} drawOutline Whether we may (re-)draw the
+ * outline of a hyperlink
+ * - {Boolean} linksOnly Whether links-only mode was
+ * active
+ */
+ onFindResult: function(aData) {
+ if (aData.result == Ci.nsITypeAheadFind.FIND_NOTFOUND) {
+ if (this._viewportChanged) {
+ if (this._targetTab != BrowserApp.selectedTab) {
+ // this should never happen
+ Cu.reportError("Warning: selected tab changed during find!");
+ // fall through and restore viewport on the initial tab anyway
+ }
+ this._targetTab.sendViewportUpdate();
+ }
+ } else {
+ // Disabled until bug 1014113 is fixed
+ // ZoomHelper.zoomToRect(aData.rect);
+ this._viewportChanged = true;
+ }
+ }
+};