Bug 1380771 - Add support for suggest_url to addEngineWithDetails. r?florian draft
authorMichael Kaply <mozilla@kaply.com>
Fri, 11 Aug 2017 16:16:41 -0500
changeset 645218 c994774c096c239b118d3f385496c3db729c0848
parent 645073 e7dc8329e2d478087314605e8184627489eef636
child 725858 d0b88c8cb8f98b58476e3d335f0e29b63eea77d8
push id73705
push usermozilla@kaply.com
push dateSat, 12 Aug 2017 00:36:53 +0000
reviewersflorian
bugs1380771
milestone57.0a1
Bug 1380771 - Add support for suggest_url to addEngineWithDetails. r?florian MozReview-Commit-ID: LoUlLwXqSOH
netwerk/base/nsIBrowserSearchService.idl
toolkit/components/search/nsSearchService.js
toolkit/components/search/tests/xpcshell/test_addEngineWithDetailsObject.js
toolkit/components/search/tests/xpcshell/xpcshell.ini
--- a/netwerk/base/nsIBrowserSearchService.idl
+++ b/netwerk/base/nsIBrowserSearchService.idl
@@ -325,41 +325,60 @@ interface nsIBrowserSearchService : nsIS
    * without starting to use it right away.
    *
    * @param name
    *        The search engine's name. Must be unique. Must not be null.
    *
    * @param iconURL
    *        Optional: A URL string pointing to the icon to be used to represent
    *        the engine.
+   *        This is a jsval so that an object can be passed to replace the
+   *        parameters below.
    *
    * @param alias
    *        Optional: A unique shortcut that can be used to retrieve the
    *        search engine.
    *
    * @param description
    *        Optional: a description of the search engine.
    *
    * @param method
-   *        The HTTP request method used when submitting a search query.
-   *        Must be a case insensitive value of either "get" or "post".
+   *        Optional: The HTTP request method used when submitting a search query.
+   *        Case insensitive value of either "get" or "post".
+   *        Defaults to "get".
    *
    * @param url
    *        The URL to which search queries should be sent.
    *        Must not be null.
    *
    * @param extensionID [optional]
    *        Optional: The correct extensionID if called by an add-on.
+   *
+   * Alternatively, all of these parameters except for name can be
+   * passed as an object in place of parameter two.
+   *
+   *   Services.search.addEngineWithDetails("Example engine", {
+   *     template: "http://example.com/?search={searchTerms}",
+   *     description: "Example search engine description",
+   *     suggestURL: http://example.com/?suggest={searchTerms},
+   * });
+   *
+   * Using this method, you can use a new parameter, suggestURL:
+   *
+   * @param suggestURL [optional]
+   *        Optional: The URL to which search suggestion requests
+   *        should be sent.
+   *
    */
   void addEngineWithDetails(in AString name,
-                            in AString iconURL,
-                            in AString alias,
-                            in AString description,
-                            in AString method,
-                            in AString url,
+                            in jsval iconURL,
+                            [optional] in AString alias,
+                            [optional] in AString description,
+                            [optional] in AString method,
+                            [optional] in AString url,
                             [optional] in AString extensionID);
 
   /**
    * Un-hides all engines installed in the directory corresponding to
    * the directory service's NS_APP_SEARCH_DIR key. (i.e. the set of
    * engines returned by getDefaultEngines)
    */
   void restoreDefaultEngines();
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -1800,30 +1800,32 @@ Engine.prototype = {
     // No need to keep a ref to our data (which in some cases can be a document
     // element) past this point
     this._data = null;
   },
 
   /**
    * Initialize this Engine object from a collection of metadata.
    */
-  _initFromMetadata: function SRCH_ENG_initMetaData(aName, aIconURL, aAlias,
-                                                    aDescription, aMethod,
-                                                    aTemplate, aExtensionID) {
+  _initFromMetadata: function SRCH_ENG_initMetaData(aName, aParams) {
     ENSURE_WARN(!this._readOnly,
                 "Can't call _initFromMetaData on a readonly engine!",
                 Cr.NS_ERROR_FAILURE);
 
-    this._urls.push(new EngineURL(URLTYPE_SEARCH_HTML, aMethod, aTemplate));
+    let method = aParams.method || "GET";
+    this._urls.push(new EngineURL(URLTYPE_SEARCH_HTML, method, aParams.template));
+    if (aParams.suggestURL) {
+      this._urls.push(new EngineURL(URLTYPE_SUGGEST_JSON, "GET", aParams.suggestURL));
+    }
 
     this._name = aName;
-    this.alias = aAlias;
-    this._description = aDescription;
-    this._setIcon(aIconURL, true);
-    this._extensionID = aExtensionID;
+    this.alias = aParams.alias;
+    this._description = aParams.description;
+    this._setIcon(aParams.iconURL, true);
+    this._extensionID = aParams.extensionID;
   },
 
   /**
    * Extracts data from an OpenSearch URL element and creates an EngineURL
    * object which is then added to the engine's list of URLs.
    *
    * @throws NS_ERROR_FAILURE if a URL object could not be created.
    *
@@ -4003,35 +4005,47 @@ SearchService.prototype = {
     for (var engineName in this._engines) {
       var engine = this._engines[engineName];
       if (engine && engine.alias == aAlias)
         return engine;
     }
     return null;
   },
 
-  addEngineWithDetails: function SRCH_SVC_addEWD(aName, aIconURL, aAlias,
-                                                 aDescription, aMethod,
-                                                 aTemplate, aExtensionID) {
+  addEngineWithDetails: function SRCH_SVC_addEWD(aName, iconURL, alias,
+                                                 description, method,
+                                                 template, extensionID) {
+    var params;
+
+    if (iconURL && typeof iconURL == "object") {
+      params = iconURL;
+    } else {
+      params = {
+        iconURL,
+        alias,
+        description,
+        method,
+        template,
+        extensionID,
+      };
+    }
+
     this._ensureInitialized();
     if (!aName)
       FAIL("Invalid name passed to addEngineWithDetails!");
-    if (!aMethod)
-      FAIL("Invalid method passed to addEngineWithDetails!");
-    if (!aTemplate)
+    if (!params.template)
       FAIL("Invalid template passed to addEngineWithDetails!");
     if (this._engines[aName])
       FAIL("An engine with that name already exists!", Cr.NS_ERROR_FILE_ALREADY_EXISTS);
 
     var engine = new Engine(sanitizeName(aName), false);
-    engine._initFromMetadata(aName, aIconURL, aAlias, aDescription,
-                             aMethod, aTemplate, aExtensionID);
+    engine._initFromMetadata(aName, params);
     engine._loadPath = "[other]addEngineWithDetails";
-    if (aExtensionID) {
-      engine._loadPath += ":" + aExtensionID;
+    if (params.extensionID) {
+      engine._loadPath += ":" + params.extensionID;
     }
     this._addEngineToStore(engine);
   },
 
   addEngine: function SRCH_SVC_addEngine(aEngineURL, aDataType, aIconURL,
                                          aConfirm, aCallback) {
     LOG("addEngine: Adding \"" + aEngineURL + "\".");
     this._ensureInitialized();
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_addEngineWithDetailsObject.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const kSearchEngineID = "addEngineWithDetails_test_engine";
+const kSearchEngineURL = "http://example.com/?search={searchTerms}";
+const kSearchSuggestURL = "http://example.com/?suggest={searchTerms}";
+const kIconURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
+const kDescription = "Test Description";
+const kAlias = "alias_foo"
+const kSearchTerm = "foo";
+const kExtensionID = "test@example.com";
+const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json";
+
+add_task(async function test_addEngineWithDetails() {
+  do_check_false(Services.search.isInitialized);
+
+  Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF)
+          .setBoolPref("reset.enabled", true);
+
+  await asyncInit();
+
+  Services.search.addEngineWithDetails(kSearchEngineID, {
+    template: kSearchEngineURL,
+    description: kDescription,
+    iconURL: kIconURL,
+    suggestURL: kSearchSuggestURL,
+    alias: "alias_foo",
+    extensionID: kExtensionID,
+  });
+
+  // An engine added with addEngineWithDetails should have a load path, even
+  // though we can't point to a specific file.
+  let engine = Services.search.getEngineByName(kSearchEngineID);
+  do_check_eq(engine.wrappedJSObject._loadPath, "[other]addEngineWithDetails:" + kExtensionID);
+  do_check_eq(engine.description, kDescription);
+  do_check_eq(engine.iconURI.spec, kIconURL);
+  do_check_eq(engine.alias, kAlias);
+
+  // Set the engine as default; this should set a loadPath verification hash,
+  // which should ensure we don't show the search reset prompt.
+  Services.search.currentEngine = engine;
+
+  let expectedURL = kSearchEngineURL.replace("{searchTerms}", kSearchTerm);
+  let submission =
+    Services.search.currentEngine.getSubmission(kSearchTerm, null, "searchbar");
+  do_check_eq(submission.uri.spec, expectedURL);
+  let expectedSuggestURL = kSearchSuggestURL.replace("{searchTerms}", kSearchTerm);
+  let submissionSuggest =
+    Services.search.currentEngine.getSubmission(kSearchTerm, URLTYPE_SUGGEST_JSON);
+  do_check_eq(submissionSuggest.uri.spec, expectedSuggestURL);
+});
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -91,13 +91,14 @@ tags = addons
 [test_selectedEngine.js]
 [test_geodefaults.js]
 [test_hidden.js]
 [test_currentEngine_fallback.js]
 [test_require_engines_in_cache.js]
 [test_svg_icon.js]
 [test_searchReset.js]
 [test_addEngineWithDetails.js]
+[test_addEngineWithDetailsObject.js]
 [test_addEngineWithExtensionID.js]
 [test_chromeresource_icon1.js]
 [test_chromeresource_icon2.js]
 [test_engineUpdate.js]
 [test_paramSubstitution.js]