My objective for this release was to dynamically "Remove" a search engine that Firefox 3 (i.e. Minefield) dynamically "Added" from a web site with a search plugin. I achieved this by building on my work from Release v.02, which dynamically "Adds" a search engine when Firefox 3 loads a web page with a search plugin.
The dynamic addition and removal of search engines presents some challenges when considering the user interface design. A few things that I considered were how to change the functionality of the searchbar while keeping it helpful and intuitive to use. I believe that it is important to keep features relatively simple and easy to use while providing some good utilitarian value to the user's web browsing experience, and not making the feature too obtrusive to the user. There are probably many Firefox users who are not aware of the searchbar's current ability to auto-detect OpenSearch plugins. Hopefully, by extending the searchbar's functionality, it will enable users to gain more benefit from it.
I arrived at a release that dynamically "Adds" a search engine when Firefox 3 navigates to a site with an OpenSearch search plugin. The newly added engine appears as the current engine on the searchbar and it can be used to search the web site. Click on images below to enlarge them.
If still on the site with the search plugin, the search engine is placed on the list of available engines as an "Add <Search Engine>" searchbar menu item when the user opens the searchbar popup.
When the user navigates to a different web site, the search engine will be dynamically removed and will not appear on the searchbar menu.
The user can navigate to a web site with an OpenSearch plugin and manually "Add" the search engine.
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.
The user may "Remove" the search engine as usual.
The removed engine appears as an "Add <Search Engine>" searchbar menu item when the user opens the searchbar popup.
The removed search engine will not appear on the searchbar menu after the user navigates to a different web site.
Excerpts of JavaScript code from the patch file are discussed and shown below.
Patch File Code Discussion - Release v.03
File: 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.
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;
}
}
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.
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);
File: nsIBrowserSearchService.idl
addEngine() Interface:
Change the return type of the interface from void to an nsISearchEngine object.
* @returns the created engine.
*/
nsISearchEngine addEngine(in AString engineURL, in long dataType, in AString iconURL,
in boolean confirm);
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.
/** The dynamically added search engine. Set to null when
* the dynamically added engine is removed.
*/
attribute nsISearchEngine dynamicEngine;
File: nsSearchService.js
Create a field named _dynamicEngine and initialize it to null.
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,
addEngine() function:
Return an nsISearchEngine object.
removeEngine() function:
return engine;
},
Set the _dynamicEngine field's value to null when an engine is removed.
this._dynamicEngine = null;
Get and set the value of the dynamicEngine attribute's value.
// 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;
},
File: search.xml
Create the dynamicEngine property to get the dynamic engine's value from the search service.
<!-- Returns the dynamicEngine from the search service. -->
<property name="dynamicEngine" readonly="true">
<getter><![CDATA[
var dynamicEngine = this.searchService.dynamicEngine;
return dynamicEngine;
]]></getter>
</property>
rebuildPopupDynamic() method:
When navigating to a site with an OpenSearch plugin and the user clicks the searchbar's button to display the engine list, remove the dynamically added search engine if it is on the list so that it will display as a searchbar "Add <Search Engine>" menu item. Use the search service removeEngine() function to remove the dynamically added search engine if it has a non-null value.
// 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" item to the list of installed engines.
if (this.dynamicEngine)
this.searchService.removeEngine(this.dynamicEngine);