note (5 February 2016): these docs are old and out of date. UnifiedComplete.js has changed how autocomplete works in Firefox. don't rely on this information when exploring the code.
- the code lives at https://github.com/mozilla/gecko-dev, it takes a while to clone it (a few gigs of data plus 400,000 commits), start the clone process and then go get lunch
-
TL;DR:
./mach build && ./obj-x86_64-apple-darwin14.1.0/dist/Nightly.app/Contents/MacOS/firefox-bin -P "foo" -purgecaches
-
./mach build
- should take 15ish minutes first time around, much less time thereafter (around 30-45 sec)
- the build process creates an output directory called
obj-<whatever>
, which contains a firefox build with your changes- in the example above, it's
obj-x86_64-apple-darwin14.1.0
- in the example above, it's
- on mac, the path to the firefox binary under that
obj-foo
directory is./dist/Nightly.app/Contents/MacOS/firefox.bin
- if you already have a copy of FF running, add
-P "profileName"
to open it with some other profile
- if you already have a copy of FF running, add
- the
-purgecaches
argument is needed to reload XUL, XBL, and JS/JSM
- The autocomplete popup is tricky to inspect because it disappears on click. In order to examine the XUL structure, shift+right click on one of the rows to open an inspector that shows the XUL DOM structure, see screenshot:
- To open devtools on browser components, you'll want to enable and open the Browser Toolbox
It looks like the autocomplete code loosely binds a dropdown box and search providers, as well as providing caching for that particular field. So, any XUL form field could provide autocomplete search of history or previously-entered strings. There is also a notion of a remote autocomplete service, so there's already some code to handle firing an XHR at a server and expecting a specific type of response. Rather than mess with that base autocomplete class (which is used everywhere), we will be better off to create our own custom autocomplete provider and our own custom autocomplete popup UI.
-
MDN docs for using autocomplete within XUL
-
Implementing a custom autocomplete search component: simple instructions with an example
- It's basically just implementing the
nsIAutoCompleteSearch
interface correctly & registering it correctly as a service - https://developer.mozilla.org/en-US/docs/How_to_implement_custom_autocomplete_search_component
- It's basically just implementing the
-
Working with XUL popups, like the autocomplete results dropdown: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/PopupGuide
-
Working with windows from XUL: opening windows, accessing content windows, passing data between windows (many approaches): https://developer.mozilla.org/en-US/docs/Working_with_windows_in_chrome_code
-
Messaging between web content and chrome (code snippets): https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
- basically, either custom DOM events or postMessage
- if postMessage, the final arg to the event listener in privileged chrome code must be 'true'
- a third option: Chromium-style JSON message passing
- there's also the Message Manager
- and vladikoff's library that abstracts the Message Manager, making it easy to send messages back and forth
-
Displaying HTML inside XUL using iframes:
- iframe vs browser XUL element types: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Tutorial/Content_Panels
- XUL iframe defn (!= HTML iframe defn) https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/iframe
- how to reduce permissions granted to web content inside a XUL iframe (XUL iframes, even if loading untrusted content, have root-level permissions by default): https://developer.mozilla.org/en-US/docs/Displaying_web_content_in_an_extension_without_security_issues
- we will be rendering external content in our results, so we want to treat it as untrusted
- If you customize Firefox UI with the Customize builder, the results will be stored in the profile, in a file called
xulstore.json
.- If you customize so that the searchbar is removed, then
xulstore['chrome://browser/content/browser.xul']['nav-bar'].currentset
becomes'urlbar-container,bookmarks-menu-button,downloads-button,home-button,loop-button'
. - This file is not present by default, so faking it seems difficult/error-prone. Maybe we can hook into the customization behavior (it's probably an XPCOM service?) rather than simply hiding the searchbar via some kind of CSS hack at XUL load time.
- If you customize so that the searchbar is removed, then
-
adding search providers is ridiculously easy: https://developer.mozilla.org/en-US/Add-ons/Creating_OpenSearch_plugins_for_Firefox
-
SUMO page explaining how to enable different kinds of content in urlbar autocomplete results: https://support.mozilla.org/en-US/kb/awesome-bar-find-your-bookmarks-history-and-tabs#w_how-can-i-control-what-results-the-location-bar-shows-me
-
ancient mozillazine article includes links to Firefox 3-era urlbar modifier addons: http://kb.mozillazine.org/Disabling_autocomplete_%28Firefox%29
Guide to Mozilla source code structure https://developer.mozilla.org/en-US/docs/Mozilla_Source_Code_Directory_Structure
Beware: MDN doesn't distinguish between obsolete xpfe interfaces (like nsIAutoCompleteItem
) and toolkit interfaces used in modern Firefox. Everything we care about is under the top-level /toolkit
module.
TODO: this needs another pass, the code is in a semi-refactored state, MDN is slightly inaccurate, need to reconcile everything
-
Major interfaces used by the autocomplete service:
nsIAutoCompleteSearch
(MDN docs, C++ interface source) - object representing autocomplete search provider as an XPCOM service. (Note, theSearchSuggestionController
(toolkit/components/search/SearchSuggestionController.jsm
) code comments say it was extracted from thensSearchSuggestions.jsm
file to remove the dependency on thensIAutoCompleteSearch
interface. Not yet sure why.)- Exposes a single method,
startSearch
, which is passed the search query, and annsIAutoCompleteObserver
that accepts results in the form of annsIAutoCompleteResult
object. (This is a simplified summary; see the MDN page for full details and optional parameters.)
- Exposes a single method,
nsIAutoCompleteObserver
(MDN docs, dxr code) - exposesonSearchResult
andonUpdateSearchResult
methods (updating allows for asynchronous insertion of values from a remote service, I think).nsIAutoCompleteResult
(MDN docs, dxr code) - represents the result of a search. The interface name is a bit ambiguous - this isn't an individual result from a search, it's an individual response from the search service for a given query. Contains result status (did search find a match, not find a match, or timeout); result count; and the actual results.nsIAutoCompleteSimpleResult
, an interesting subclass (C++ idl, header file, C++ impl) - used by satchel'snsFormFillController
, and the placesnsPlacesAutoComplete.js
andUnifiedComplete.js
files, TODO explore further
-
Major interfaces used by the autocomplete UI layer (TODO needs updating):
nsIAutoCompleteController
- it's a controller but doesn't directly observe DOM; instead, observes user input / key press events fired by ansIAutoCompleteInput
, which could either be a XUL autocomplete textbox or a form fill controller that handles website form historynsIAutoCompleteInput
- monitors the input in a text field and displays an autocomplete panel at the appropriate timensIAutoCompletePopup
(C++ interface, XUL implementation) - binds annsIAutoCompleteInput
object to annsIDOMElement
/browser/base/content/browser.js
- assembles the modules
gURLBar
is defined here on the global window object
-
/browser/base/content/browser.xul
- defines an
autocomplete-richtextbox
entity (i.e. an xml tag name)- this corresponds to
PopupAutoCompleteRichResult
- which is defined in
components/search/content/search.xml
- this corresponds to
- defines an
-
/browser/base/content/urlbarBindings.xml
- urlbar UI handlers defined inside an XML file
- urlbar extends
content/bindings/autocomplete.xml
, not sure if that really meanstoolkit/content/widgets/autocomplete.xml
which seems to have similar stuff in it
-
/toolkit/content/widgets/autocomplete.xml
- UI definitions for the autocomplete UI that drops down
/toolkit/components/autocomplete/nsAutoCompleteController.cpp
HandleText
method contains logic around when to search & waiting for user to stop typingStartSearches
method - set a timer, callStartSearch
StartSearch
- loop overmSearches
, callstartSearch
on (some of) themSetInput
- assemblemSearches
by getting pointers to search services, specifically, by getting a "contract id string" from an instance of thensIAutoCompleteInput
interface.
These are implementations of autocomplete interfaces I've found in the gecko codebase:
-
/toolkit/components/places
- TODO look at other files in this directory
/toolkit/components/places/nsPlacesAutoComplete.js
- This file is incredibly helpful. We can lean on this implementation when defining our own autocomplete implementation (though we need to investigate how other search providers integrate into autocomplete. I've found an OpenSearch specification, need to explore further)
- Autocomplete strings are sent here, to be queried against the Places SQLite DB
- see "Smart Getters" section for SQL queries corresponding to keyword, bookmark, "frecency", etc searches
startSearch
function is very helpful reading
-
/toolkit/components/filepicker
- Looks like an implementation of the autocomplete service interfaces:
nsFileComplete
- C++ code, implementsnsIAutoCompleteSearch
nsFileResult
- C++ code, implementsnsIAutoCompleteResult
- I don't see autocomplete-specific UI elements. Instead, I see classic MVC:
/tookit/components/filepicker/content/filepicker.xul
- a very simple View: template for the file picker dialognsFilePicker
(/toolkit/components/filepicker/nsFilePicker.js
) - a large Model: operates on the underlying file system using various C++ iterators/enumerators; manages the results by setting properties on itself; its state is rendered into thefilepicker.xul
file picker dialog by thefilepicker.js
controllernsFileView
- (
C++ interface
,C++ class
) - implementsnsITreeView
- looks like a base C++ class and interface, I'm not totally clear on the boundary between C++ and JS implementations of these interfaces JS implementation
(/toolkit/components/filepicker/content/filepicker.js
) - a Controller: binds handlers for click and other DOM events; updates the View (in this case, a dumb XUL template) with results; all the data seems to live in thensFilePicker.js
model.
- (
- Looks like an implementation of the autocomplete service interfaces:
-
toolkit/components/satchel
- need to read this and figure out what it does
-
OpenSearch is an XML spec describing search provider endpoints
- https://developer.mozilla.org/en-US/Add-ons/Creating_OpenSearch_plugins_for_Firefox
- examples are localized, see, eg,
browser/locales/en-US/searchplugins
-
browser/base/content/searchSuggestionUI.js
- creates an xhtml table, inserts into DOM after a given textbox el, styles it to look like a dropdown
- emits
GetSuggestions
signal with packet format{engineName, searchString, remoteTimeout}
- listens for
ContentSearchService
events onwindow
- note,
/browser/base/content/content.js
contains aContentSearchMediator
which:- listens for
ContentSearchClient
andContentSearch
signals - checks them against some kind of whitelist (need to look more deeply at this)
- if ok, republishes them as
ContentSearchService
events
- listens for
- note,
-
netwerk/base/nsIBrowserSearchService.idl
- C++ interface defining a remote service facade
-
toolkit/components/search/nsSearchService.js
- basically a service facade, abstracts an OpenSearch endpoint
- instantiates an Engine, sends requests, returns responses to caller
- maintains a sorted array of Engines
- also includes
engineMetadataService
(modifies & saves engine attributes to disk),engineUpdateService
(checks for engine definition updates, modifies local Engines as needed)
-
toolkit/components/search/SearchSuggestionController.js
- helper module, code comments say it was factored out of
nsSearchSuggestions
to allow multiple consumers to request & display search suggestions from a given Engine (implementation ofnsISearchEngine
) - caches form history results
- since it provides caching & recent search history, designed to use one of these per textbox
- searches & returns both recent history and remote search suggestions
- interesting methods:
SearchSuggestionController::fetch
- for each search, look it up in form history cache & fetch from remote suggestion service, if enabledSearchSuggestionController::_fetchFormHistory
- get annsIAutoCompleteSearch
implementation, callstartSearch
on it, handle responseSearchSuggestionController::_fetchRemote
- given an engine (nsISearchEngine
), get the URL viaengine.getSubmission
, then create & send an XHR
- helper module, code comments say it was factored out of
-
toolkit/components/search/nsSearchSuggestions.js
- defines
SuggestAutoComplete
, base implementation ofnsIAutoCompleteSearch
- I think (not sure) input from the front-end is handled by
nsSearchSuggestionController
- sends output to front-end by:
- creating & returning a
FormAutoCompleteResult
containing the result data - sending it to the caller (who must implement
nsIAutoCompleteObserver
)
- creating & returning a
- fetches results from search service accessed via
Services.search
- search results are collected/aggregated by the
SearchSuggestionController
- defines
- Overview MDN docs:
- Mochitest: framework for JS-based automation of browser stuff for testing
- we can use this to automate key presses to see how relevant our results are over time
- we will also need lots of tests to land anything in desktop
- https://developer.mozilla.org/en-US/docs/Mochitest
- there is some kind of slightly different thing for testing browser chrome: