Localized Search in Firefox Search Box: Release v.03

From CDOT Wiki
Revision as of 23:04, 28 February 2008 by Sinker (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Main Project Page

Localized Search in Firefox Search Box

Release v.03

This release (v.03) dynamically removes the auto-detected search engine when the user navigates to a different web site unless the user selects the "Add <Search Engine>" menu item from the searchbar's list of available engines to install the search engine. For example, the auto-detected search engine is dynamically added and appears as the current engine when the user navigates to a site with an OpenSearch plugin. The engine can be used immediately to search the site without the user having to manually "Add" it. When the user clicks the searchbar's button to display the engine list, the dynamically "Added" search engine is then put on the list of engines as an "Add <Search Engine>" menu item . At that point, the user can choose to manually "Add" the auto-detected search plugin and it will remain on the list of installed engines when the user navigates to another web site.


Patch File - localsearchpatch_v03.txt

? localsearchpatch_v03.txt
? nohup.out
? objdir-ff-debug
Index: browser/base/content/browser.js
===================================================================
RCS file: /cvsroot/mozilla/browser/base/content/browser.js,v
retrieving revision 1.966
diff -u -8 -p -r1.966 browser.js
--- browser/base/content/browser.js	17 Feb 2008 05:26:52 -0000	1.966
+++ browser/base/content/browser.js	21 Feb 2008 21:38:07 -0000
@@ -2788,16 +2788,24 @@ const BrowserSearch = {
     // If this engine (identified by title) is already in the list, add it
     // to the list of hidden engines rather than to the main list.
     // XXX This will need to be changed when engines are identified by URL;
     // see bug 335102.
     var searchService = Cc["@mozilla.org/browser/search-service;1"].
                         getService(Ci.nsIBrowserSearchService);
     if (searchService.getEngineByName(engine.title))
       hidden = true;
+    else {
+        // Dynamically "Add" the web site's search engine plugin.
+        var addedEngine = searchService.addEngine(engine.href, Components.interfaces.nsISearchEngine.DATA_XML, iconURL, false);
+        if (addedEngine) {
+          searchService.dynamicEngine = addedEngine;
+          hidden = true;
+        }
+    }
 
     var engines = (hidden ? browser.hiddenEngines : browser.engines) || [];
 
     engines.push({ uri: engine.href,
                    title: engine.title,
                    icon: iconURL });
 
     if (hidden)
@@ -3857,18 +3865,26 @@ nsBrowserStatusHandler.prototype =
     this.onProgressChange(gBrowser.webProgress, 0, 0, aTotalProgress, 1);
   },
 
   startDocumentLoad : function(aRequest)
   {
     // clear out feed data
     gBrowser.mCurrentBrowser.feeds = null;
 
+    var searchService = Cc["@mozilla.org/browser/search-service;1"].
+                        getService(Ci.nsIBrowserSearchService);
+    var dynamicEngine = searchService.dynamicEngine;
+
+    // Remove the dynamically added search engine if it is on the list.
+	  if (dynamicEngine)
+      searchService.removeEngine(dynamicEngine);
+
     // clear out search-engine data
-    gBrowser.mCurrentBrowser.engines = null;    
+    gBrowser.mCurrentBrowser.engines = null;  
 
     const nsIChannel = Components.interfaces.nsIChannel;
     var urlStr = aRequest.QueryInterface(nsIChannel).URI.spec;
     var observerService = Components.classes["@mozilla.org/observer-service;1"]
                                     .getService(Components.interfaces.nsIObserverService);
     try {
       observerService.notifyObservers(content, "StartDocumentLoad", urlStr);
     } catch (e) {
Index: browser/components/search/nsIBrowserSearchService.idl
===================================================================
RCS file: /cvsroot/mozilla/browser/components/search/nsIBrowserSearchService.idl,v
retrieving revision 1.20
diff -u -8 -p -r1.20 nsIBrowserSearchService.idl
--- browser/components/search/nsIBrowserSearchService.idl	11 Sep 2007 16:07:11 -0000	1.20
+++ browser/components/search/nsIBrowserSearchService.idl	21 Feb 2008 21:38:08 -0000
@@ -187,19 +187,21 @@ interface nsIBrowserSearchService : nsIS
    * @param confirm
    *        A boolean value indicating whether the user should be asked for
    *        confirmation before this engine is added to the list.  If this
    *        value is false, the engine will be added to the list upon successful
    *        load, but it will not be selected as the current engine.
    *
    * @throws NS_ERROR_FAILURE if the type is invalid, or if the description
    *         file cannot be successfully loaded.
+   *
+   * @returns the created engine.
    */
-  void addEngine(in AString engineURL, in long dataType, in AString iconURL,
-                 in boolean confirm);
+  nsISearchEngine addEngine(in AString engineURL, in long dataType, in AString iconURL,
+                 	    in boolean confirm);
 
   /**
    * Adds a new search engine, without asking the user for confirmation and
    * without starting to use it right away.
    *
    * @param name
    *        The search engine's name. Must be unique. Must not be null.
    *
@@ -316,16 +318,21 @@ interface nsIBrowserSearchService : nsIS
   readonly attribute nsISearchEngine defaultEngine;
 
   /**
    * The currently active search engine. May be null if there are no visible
    * search engines installed.
    */
   attribute nsISearchEngine currentEngine;
 
+  /** The dynamically added search engine. Set to null when
+   *  the dynamically added engine is removed.
+   */
+  attribute nsISearchEngine dynamicEngine;
+
 };
 
 %{ C++
 /**
  * The observer topic to listen to for actions performed on installed
  * search engines.
  */
 #define SEARCH_ENGINE_TOPIC "browser-search-engine-modified"
Index: browser/components/search/nsSearchService.js
===================================================================
RCS file: /cvsroot/mozilla/browser/components/search/nsSearchService.js,v
retrieving revision 1.108
diff -u -8 -p -r1.108 nsSearchService.js
--- browser/components/search/nsSearchService.js	29 Jan 2008 19:39:20 -0000	1.108
+++ browser/components/search/nsSearchService.js	21 Feb 2008 21:38:09 -0000
@@ -2214,16 +2214,19 @@ function SearchService() {
 }
 SearchService.prototype = {
   _engines: { },
   _sortedEngines: null,
   // Whether or not we need to write the order of engines on shutdown. This
   // needs to happen anytime _sortedEngines is modified after initial startup. 
   _needToSetOrderPrefs: false,
 
+  // The dynamically added engine.
+  _dynamicEngine: null,
+
   _init: function() {
     var prefB = Cc["@mozilla.org/preferences-service;1"].
                 getService(Ci.nsIPrefBranch);
     var shouldLog = false;
     try {
       shouldLog = prefB.getBoolPref(BROWSER_SEARCH_PREF + "log");
     } catch (ex) {}
 
@@ -2731,16 +2734,17 @@ SearchService.prototype = {
       var engine = new Engine(uri, aDataType, false);
       engine._initFromURI();
     } catch (ex) {
       LOG("addEngine: Error adding engine:\n" + ex);
       throw Cr.NS_ERROR_FAILURE;
     }
     engine._setIcon(aIconURL, false);
     engine._confirm = aConfirm;
+    return engine;
   },
 
   removeEngine: function SRCH_SVC_removeEngine(aEngine) {
     ENSURE_ARG(aEngine, "no engine passed to removeEngine!");
 
     var engineToRemove = null;
     for (var e in this._engines)
       if (aEngine.wrappedJSObject == this._engines[e])
@@ -2768,16 +2772,18 @@ SearchService.prototype = {
              Cr.NS_ERROR_FAILURE);
       this._sortedEngines.splice(index, 1);
 
       // Remove the engine from the internal store
       delete this._engines[engineToRemove.name];
 
       notifyAction(engineToRemove, SEARCH_ENGINE_REMOVED);
 
+      this._dynamicEngine = null;
+
       // Since we removed an engine, we need to update the preferences.
       this._needToSetOrderPrefs = true;
     }
   },
 
   moveEngine: function SRCH_SVC_moveEngine(aEngine, aNewIndex) {
     ENSURE_ARG((aNewIndex < this._sortedEngines.length) && (aNewIndex >= 0),
                "SRCH_SVC_moveEngine: Index out of bounds!");
@@ -2839,16 +2845,27 @@ SearchService.prototype = {
     const defPref = BROWSER_SEARCH_PREF + "defaultenginename";
     // Get the default engine - this pref should always exist, but the engine
     // might be hidden
     this._defaultEngine = this.getEngineByName(getLocalizedPref(defPref, ""));
     if (!this._defaultEngine || this._defaultEngine.hidden)
       this._defaultEngine = this._getSortedEngines(false)[0] || null;
     return this._defaultEngine;
   },
+ 
+  // Get the dynamically added engine.
+  get dynamicEngine() {
+    return this._dynamicEngine;
+  },
+  // Set the dynamically added engine.
+  set dynamicEngine(val) {
+    ENSURE_ARG(val instanceof Ci.nsISearchEngine,
+               "Invalid argument passed to dynamicEngine setter");
+    this._dynamicEngine = val;
+  },
 
   get currentEngine() {
     if (!this._currentEngine || this._currentEngine.hidden)
       this._currentEngine = this.defaultEngine;
     return this._currentEngine;
   },
   set currentEngine(val) {
     ENSURE_ARG(val instanceof Ci.nsISearchEngine,
Index: browser/components/search/content/search.xml
===================================================================
RCS file: /cvsroot/mozilla/browser/components/search/content/search.xml,v
retrieving revision 1.120
diff -u -8 -p -r1.120 search.xml
--- browser/components/search/content/search.xml	6 Feb 2008 19:00:09 -0000	1.120
+++ browser/components/search/content/search.xml	21 Feb 2008 21:38:10 -0000
@@ -168,16 +168,24 @@
                 onset="this.searchService.currentEngine = val; return val;">
         <getter><![CDATA[
           var currentEngine = this.searchService.currentEngine;
           // Return a dummy engine if there is no currentEngine
           return currentEngine || {name:"", uri:null};
         ]]></getter>
       </property>
 
+       <!-- Returns the dynamicEngine from the search service. -->
+       <property name="dynamicEngine" readonly="true">
+        <getter><![CDATA[
+          var dynamicEngine = this.searchService.dynamicEngine;
+          return dynamicEngine;
+        ]]></getter>
+      </property>
+
       <!-- textbox is used by sanitize.js to clear the undo history when
            clearing form information. -->
       <property name="textbox" readonly="true"
                 onget="return this._textbox;"/>
 
       <property name="searchService" readonly="true">
         <getter><![CDATA[
           if (!this._ss) {
@@ -326,16 +334,22 @@
       </method>
 
       <!-- Rebuilds the dynamic portion of the popup menu (i.e., the menu items
            for new search engines that can be added to the available list).  This
            is called each time the popup is shown.
       -->
       <method name="rebuildPopupDynamic">
         <body><![CDATA[
+    	  // Remove the dynamically added search engine if it is on the list when
+	  // the popup's menu items are first displayed. The user may then choose
+	  // to add the "Add <Search Engine>" item to the list of installed engines.
+	  if (this.dynamicEngine)
+            this.searchService.removeEngine(this.dynamicEngine);
+
           // We might not have added the main popup items yet, do that first
           // if needed.
           if (this._needToBuildPopup)
             this.rebuildPopup();
 
           var popup = this._popup;
           // Clear any addengine menuitems, including addengine-item entries and
           // the addengine-separator.  Work backward to avoid invalidating the


Code Modifications

1. browser.js

  • addEngine() function: If the auto-detected search plugin is NOT on the search service's list of engines, then dynamically "Add" the search engine and assign it to the addedEngine local variable. Set the search service's dynamicEngine attribute to the value of the newly added engine.
  • startDocumentLoad() function: When the user navigates to a different web site, get an instance of nsIBrowserSearchService and assign it to the variable searchService. Get the search service's dynamicEngine attribute and assign it to the dynamicEngine local variable. Then, if dynamicEngine has a non-null value, use the search service's removeEngine() function to remove it from the list.


2. nsIBrowserSearchService.idl

  • addEngine() Interface: Change the return type of the interface from void to an nsISearchEngine object.
  • Create an attribute named dynamicEngine of the type nsISearchEngine to hold the value of a dynamically added search engine that can be set to null when the engine is removed.


3. nsSearchService.js

  • Create a field named _dynamicEngine and initialize it to null.
  • addEngine() function: Return an nsISearchEngine object.
  • removeEngine() function: Set the _dynamicEngine field's value to null when an engine is removed.
  • Get and set the value of the dynamicEngine attribute's value.


4. search.xml

  • Create the dynamicEngine property to get the dynamic engine's value from the search service.
  • rebuildPopupDynamic() method: When the user first clicks the searchbar's button to display the engine list, remove the dynamically added search engine if it has a non-null value so that it appears as an "Add <Search Engine>" menu item. Use the search service removeEngine() function to remove it.


How to Use the Patch (Screenshots)

1. Copy and paste all of the text from the patch file into a text file and name the file localsearchpatch_v031.txt. Save the file to your root mozilla directory. Then, apply the patch and recompile your mozilla source code as described in the release v.01 notes.


2. Start-up Firefox 3 (i.e. Minefield) and go to a web site that offers a search engine plugin.


FFLocalSearchv03 ss01.png


  • Notice that the search plugin has been dynamically loaded and added to the searchbar's list of installed engines. The newly added search engine appears as the current engine and it can be used to search the web site.


3. Click Firefox's searchbar button to display the list of search engines. Observe that the dynamically loaded search plugin is no longer on the list of installed engines and it is now listed as an "Add <Search Engine>" menu item.


FFLocalSearchv03 ss05.png


  • NOTE: If you opt to manually "Add" the engine to the list of installed engines, it will remain as an installed engine when you navigate to a different web site. That is its normal behavior.


4. Navigate to a web site that does NOT offer a search plugin. Observe that the dynamically "Added" search engine is no longer on the searchbar's list.


FFLocalSearchv03 ss00.png


5. Navigate to a web site with an OpenSearch plugin and manually "Add" the search engine.


FFLocalSearchv03 ss05.png


  • NOTE: The manually added engine will NOT be dynamically removed from the installed engines list on the searchbar when the user navigates to a different web site.


FFLocalSearchv03 ss06.png


6. Open the Search Engine Manager's dialog and "Remove" a manually "Added" search engine.


FFLocalSearchv03 ss07.png


  • Notice that it is no longer on the list of installed engines and it is now listed as an "Add <Search Engine>" menu item; that is its normal behavior. If you choose to "Add" the engine back to the list of installed engines, it will remain as an installed engine when you navigate to a different web site.


FFLocalSearchv03 ss08.png


Return to top