diff --git a/browser/components/extensions/ext-browser.js b/browser/components/extensions/ext-browser.js
--- a/browser/components/extensions/ext-browser.js
+++ b/browser/components/extensions/ext-browser.js
@@ -148,16 +148,24 @@ extensions.registerModules({
devtools_panels: {
url: "chrome://browser/content/ext-devtools-panels.js",
schema: "chrome://browser/content/schemas/devtools_panels.json",
scopes: ["devtools_parent"],
paths: [
["devtools", "panels"],
],
},
+ find: {
+ url: "chrome://browser/content/ext-find.js",
+ schema: "chrome://browser/content/schemas/find.json",
+ scopes: ["addon_parent"],
+ paths: [
+ ["find"],
+ ],
+ },
history: {
url: "chrome://browser/content/ext-history.js",
schema: "chrome://browser/content/schemas/history.json",
scopes: ["addon_parent"],
paths: [
["history"],
],
},
diff --git a/browser/components/extensions/ext-find.js b/browser/components/extensions/ext-find.js
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-find.js
@@ -0,0 +1,115 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+this.find = class extends ExtensionAPI {
+ getAPI(context) {
+ return {
+ find: {
+ /**
+ * browser.find.search
+ * Searches document and its frames for a given queryphrase and stores all found
+ * Range objects in an array accessible by other browser.find methods.
+ *
+ * @param {object} query
+ * @param {string} query.queryphrase
+ * The string to search for.
+ * @param {integer} query.tabId optional
+ * Tab to query. Defaults to the active tab.
+ * @param {boolean} query.caseSensitive optional
+ * Highlight only ranges with case sensitive match.
+ * @param {boolean} query.entireWord optional
+ * Highlight only ranges that match entire word.
+ * @param {boolean} query.includeRectData optional
+ * Whether to return rectangle data.
+ * @param {boolean} query.includeRangeData optional
+ * Whether to return range data.
+ *
+ * @returns a promise that will be resolved when search is completed.
+ */
+ search(query) {
+ let { queryphrase, tabId, caseSensitive, entireWord, includeRectData, includeRangeData } = query;
+ let tab = tabId ? tabTracker.getTab(tabId) : tabTracker.activeTab;
+ let browser = tab.linkedBrowser;
+ let finder = browser.finder;
+ tabId = tabId || tabTracker.getId(tab);
+
+ return new Promise(resolve => {
+ if (browser.isRemoteBrowser) {
+ let mm = browser.messageManager;
+ mm.addMessageListener("Finder:CollectSearchResultsFinished", function returnFindRanges(message) {
+ mm.removeMessageListener("Finder:CollectSearchResultsFinished", returnFindRanges);
+ message.data.tabId = tabId;
+ resolve(message.data);
+ });
+ finder.getSearchResults(
+ queryphrase, caseSensitive, entireWord, includeRangeData, includeRectData);
+ } else {
+ let promise = finder.getSearchResults(
+ queryphrase, caseSensitive, entireWord, includeRangeData, includeRectData);
+ promise.then((searchResults) => {
+ resolve({ tabId, searchResults });
+ });
+ }
+ });
+ },
+
+ /**
+ * browser.find.highlightResults
+ * Highlights range(s) found in previous browser.find.search.
+ *
+ * @param {object} params
+ * @param {integer} params.rangeIndex required
+ * Found range to be highlighted held in API's ranges array for the tabId.
+ * Default highlights all ranges.
+ * @param {integer} params.tabId optional
+ * Tab to highlight. Defaults to the active tab.
+ * @param {boolean} params.noScroll optional
+ * Don't scroll to highlighted item.
+ * @param {boolean} params.noRemoveHighlighting optional
+ * Don't remove previous highlighting.
+ *
+ * @returns a value describing the resulting status of the highlighting. This will be one of:
+ * 1 - success.
+ * 2 - index supplied was out of range.
+ * 3 - there were no search results to highlight.
+ */
+ highlightResults(params) {
+ let { rangeIndex, tabId, noScroll, noRemoveHighlighting } = params;
+ let tab = tabId ? tabTracker.getTab(tabId) : tabTracker.activeTab;
+ let browser = tab.linkedBrowser;
+ let finder = browser.finder;
+
+ return new Promise(resolve => {
+ if (browser.isRemoteBrowser) {
+ let mm = browser.messageManager;
+ mm.addMessageListener("Finder:HighlightSearchResultsFinished", function highlightFindRanges(message) {
+ mm.removeMessageListener("Finder:HighlightSearchResultsFinished", highlightFindRanges);
+ resolve(message.params);
+ });
+ finder.highlightSearchResults(params.rangeIndex, noScroll, noRemoveHighlighting);
+ } else {
+ let status = finder.highlightSearchResults(params.rangeIndex, noScroll, noRemoveHighlighting);
+ resolve({ status });
+ }
+ });
+ },
+
+ /**
+ * browser.find.removeHighlighting
+ * Removes all hightlighting from previous search.
+ *
+ * @param {integer} tabId optional
+ * Tab to highlight. Defaults to the active tab.
+ */
+ removeHighlighting(tabId) {
+ let tab = tabId ? tabTracker.getTab(tabId) : tabTracker.activeTab;
+ return new Promise(resolve => {
+ tab.linkedBrowser.finder.removeHighlighting();
+ resolve();
+ });
+ },
+ },
+ };
+ }
+}
diff --git a/browser/components/extensions/schemas/find.json b/browser/components/extensions/schemas/find.json
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/schemas/find.json
@@ -0,0 +1,123 @@
+// Copyright (c) 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.
+
+[
+ {
+ "namespace": "manifest",
+ "types": [
+ {
+ "$extend": "OptionalPermission",
+ "choices": [{
+ "type": "string",
+ "enum": [
+ "find"
+ ]
+ }]
+ }
+ ]
+ },
+ {
+ "namespace": "find",
+ "description": "Use the browser.find
API to interact with the browser's Find
system.",
+ "permissions": ["find"],
+ "functions": [
+ {
+ "name": "search",
+ "type": "function",
+ "async": true,
+ "description": "Search for text in document and store found ranges in array, in document order.",
+ "parameters": [
+ {
+ "name": "query",
+ "type": "object",
+ "description": "Search query parameters.",
+ "properties": {
+ "queryphrase": {
+ "type": "string",
+ "description": "The string to search for."
+ },
+ "tabId": {
+ "type": "integer",
+ "description": "Tab to query. Defaults to the active tab.",
+ "optional": true,
+ "minimum": 0
+ },
+ "caseSensitive": {
+ "type": "boolean",
+ "description": "Find only ranges with case sensitive match.",
+ "optional": true
+ },
+ "entireWord": {
+ "type": "boolean",
+ "description": "Find only ranges that match entire word.",
+ "optional": true
+ },
+ "includeRectData": {
+ "description": "Return rectangle data which describes visual position of search results.",
+ "type": "boolean",
+ "optional": true
+ },
+ "includeRangeData": {
+ "description": "Return range data which provides range data in a serializable form.",
+ "type": "boolean",
+ "optional": true
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "highlightResults",
+ "type": "function",
+ "async": true,
+ "description": "Highlight a range",
+ "parameters": [
+ {
+ "name": "params",
+ "type": "object",
+ "description": "highlightResults parameters",
+ "properties": {
+ "rangeIndex": {
+ "type": "integer",
+ "description": "Found range to be highlighted. Default highlights all ranges.",
+ "minimum": 0,
+ "optional": true
+ },
+ "tabId": {
+ "type": "integer",
+ "description": "Tab to highlight. Defaults to the active tab.",
+ "minimum": 0,
+ "optional": true
+ },
+ "noScroll": {
+ "type": "boolean",
+ "description": "Don't scroll to highlighted item.",
+ "optional": true
+ },
+ "noRemoveHighlighting": {
+ "type": "boolean",
+ "description": "Don't remove previous highlighting.",
+ "optional": true
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "removeHighlighting",
+ "type": "function",
+ "async": true,
+ "description": "Remove all highlighting from previous searches.",
+ "parameters": [
+ {
+ "name": "tabId",
+ "type": "integer",
+ "description": "Tab to highlight. Defaults to the active tab.",
+ "optional": true
+ }
+ ]
+ }
+ ]
+ }
+]