Saturday, February 2, 2008

Mozilla Project Update: Release v.01

Mozilla Project: Localized Search in Firefox Search Box - Release v.01
My main objective for this initial release is to demonstrate a basic understanding of how some of the search box (searchbar) features currently work in the Firefox browser by examining the source code. I attempt to achieve this by placing JavaScript dump() statements within the existing code. These statements output diagnostic messages to the terminal window when running a DEBUG build of Firefox 3 (i.e. Minefield). The messages contain information about what methods or functions are being called and a brief explanation about what is happening in the source code when certain searchbar events occur. These events are listed here and the more pertinent ones to my project are discussed below:
  • The browser auto-detects a site that has a search plugin available.
  • The user selects the button to display the search engine list when a search plugin is available.
  • The user selects the option to "Add <EngineName>".
  • The user changes the current search engine by selecting it from the search bar drop-down list (menu).
  • The user moves the position of a search engine using the Search Engine Manager.
  • The user removes an auto-detected search engine from the list of "installed" search engines with the Search Manager.
I created a patch that inserts the dump() statements in the code. You may preview the patch at the following location: Patch File: localsearchpatch_v01.txt . You can also get information about how to download and apply the patch on my project wiki page.

Discussion of Source Code for SearchBar Events:
When the browser detects that a web site has a search engine plugin, there are a few things that happen in the browser.js code. The browser has an event listener named "DOMLinkAdded" that employs an event handler named DOMLinkHandler. My understanding of the code is that when Firefox loads a page containing a <link> element, it triggers a DOMLinkAdded type of event. The DOMLinkHandler calls its function, onLinkAdded(event), which determines the rel attribute value of the <link> element. If it has a value of search and its type, title and href attributes have valid values, an engine object is created and passed to the BrowserSearch object's addEngine(engine, targetDoc) function. This function first checks if the engine object is already in the browser's array of "hidden" engines, and if it is, then it's pushed to the end of the browser's hiddenEngines array. If the engine object is not in the hiddenEngines array, then it is added to the browser's engines array.

When a web page has a search plugin and the user clicks the button to display the searchbar menu, an event handler named "popupshowing" calls the rebuildPopupDynamic() method in search.xml. If the main popup menu items have not been added yet, rebuildPopupDynamic() calls the rebuildPopup() method, which rebuilds the list of visible search engines in the menu. Next, the rebuildPopupDynamic() method clears any existing "Add <EngineName>" menu items from the popup menu and assigns the browser's engines array to the addengines array. Then, it inserts the elements of the addengines array as menu items onto the searchbar menu as "Add <EngineName>" menu items.

Selecting the "Add <EngineName>" menu notifies the searchbar's observe(aEngine, aTopic, aVerb) method and it calls the hideNewEngine(aEngine) method, passing it a reference to the search engine object. The hideNewEngine(aEngine) method moves the engine object to each browser's "hidden" array so it is no longer offered to be added if the engine was auto-detected on the web page. This method iterates through all of the browser's open tabs and finds the selected engine in the browser's engines array. Then, it adds the search engine to the browser's hiddenEngines array and removes it from the browser's engines array. As a further explanation, browser.js fills two arrays of auto-detected search engines (browser.engines and browser.hiddenEngines). Those arrays contain unnamed JS objects that the searchbar uses to determine whether to show any "Add <EngineName>" menu items in the drop-down list.

When the user opens the Search Engine Manager Dialog Box, selects an auto-detected search engine from the "installed" list of engines and clicks the "Remove" button, the dialog's remove() function gets called in the engineManager.js file. The remove() function then passes a reference of the selected engine to an EngineView object's removeEngine(aEngine) function. This function removes the selected engine from the array of "Visible" engines using the index of the selected engine. It also adds an EngineRemoveOp object to an array. It is this object's commit() function that gets called when the user clicks the "OK" button in the Search Engine Manager Dialog. The commit() function uses an object reference to call the removeEngine(aEngine) function defined in nsSearchService.js . This function completes the search engine removal process by removing the engine from its internal store and then removes it from disk if the file can be removed.

Removing an auto-detected search engine also notifies search.xml's observe(aEngine, aTopic, aVerb) method, which calls the offerNewEngine(aEngine) method, passing it a reference to the search engine object. This method moves the search engine to each browser's active list so that it will be available to be added again if the engine that was just removed from the searchbar menu was auto-detected on the web page. Similar to the hideNewEngine(aEngine) method, offerNewEngine(aEngine) iterates through all of the browser's open tabs and finds the engine in the browser's hiddenEngines array. Then, it adds the search engine to the browser's engines array and removes it from the browser's hiddenEngines array.

Files:
browser.js
engineManager.js
nsIBrowserSearchService.idl
nsSearchService.js
search.xml

No comments: