Firebug 1.6 Architecture Review

From FirebugWiki

Jump to: navigation, search

The goal here is to answer my questions (in bold). The typical question is usually: What is this object responsible for? What kind of logic should belong to it? What is the relation with other objects?

Contents

[edit] Architecture

Firebug-architecture.png

[edit] Application Components

(Some of this is to be changed in future)

TabContext 
(Model) Complete metadata about the web page loaded in a tab.
TabWatcher 
Registers for Firefox tab-events, Creates/destroys context objects. Dispatches web page life cycle events.
modules  
Task specific controllers. registers for events in Firefox or analyzes Firefox data during web page live cycle events.
panels  
Task specific views. Renders data out of a context into the UI.
Firebug  
(Framework) Maintains modules and panels, dispatches events between them. Initializes application (part to FirebugLoader in 1.7)
Firebug.Chrome 
Manages the non-panel part of the UI, toolbars, global option buttons.
FBL  
(Library) utility code used in more than one module/panel.
browser.xul 
Code loader (to FirebugLoader in 1.7), UI integration with Firefox UI (to HTML5 in 1.8),
firebug.xul 
Code loader, UI for detached Firebug (to HTML5 in 1.8),
FirebugLoader 
(new) Called by Firefox to initialize Firebug, loads JS code, manages first-time-up UI.
XULWindowWatcher 
(new) UI integration with one XUL (Firefox) window
firebug-service 
component interface to platform jsd (a per application module in 1.7)

[edit] Organization Units

Per application 
firebug-service, firebug-channel-listener, firebug-http-observer, firebug-trace-service, storageService, (FirebugLoader in 1.7)
Per Firefox window 
Firebug, modules, TabWatcher, browser.xul, (XULWindowWatcher in 1.7)
Per Firebug window 
Firebug.Chrome, panels, firebug.xul

[edit] Architecture Constraints

  • TabWatcher should encapsulate all interaction with Firefox tabBrowser.
  • "window" in chrome.js means the window containing the Firebug user interface managed by chrome.js
  • "window" in firebug.js means one Firefox XUL window. (to XULWindowWatcher in 1.7)
  • FirebugLoader should be component known to Firefox before loading
    • responsible for initialization of all namespaces.
  • Modules should not operate on Panels; panels should not operate on modules (Panels violate this now)
    • They need to communicate by putting data on the context.
    • Common code needs to be factored in to lib or lib/module_name_lib.js

  • TabWatcher should be registered as a provider of context creation events: initContext, destroyContext, etc (see also firebug.js comment "To be called from TabWatcher only, see selectContext).
  • tabBrowser (main-window) is now accessed from FirebugChrome, FBL, Firebug and TabWatcher objects. While it should be only used by TabWatcher.
  • The (new) application loader should create TabWatcher, TabWatcher should register with Firebug, then provide context creation events. The new application loader will deal with configuration and initialization; configuration may vary with Firefox, Fennec, remote/local...
    • What do you refer by "the (new) application loader"?
  • FirebugChrome is a global pointing to the Firebug.Chrome (chrome.js) object in this scope. Firebug.Chrome should controller code for the firebug.xul, code for the tool bars around the panels. The stuff we call 'UI' in the bug list.
  • Bindings and Browser represents the only entities that use XUL. These would be replaced in case Firebug UI is entirely HTML.
    • the script tag list in browser.xul will become part of the configuration list fed to the new application loader. I don't understand this comment.

[edit] Initialization

  • Solid lines represent function calls. Dashed lines represents event dispatch (based on FBL.dispatch and FBL.dispatch2).

Firebug-initialization-sequence.png

  • Event initializeUI should not be dispatched to Module. This is currently used only by ActivationModule and should be removed.
  • Panels are created and initialized by TabContext as soon as they are needed.

[edit] Detach

Detaching Firebug UI (into a new XUL window) is like initialization in another window.

Firebug-detach-sequence.png

  • The initialization process is the same till initializeUI event.
  • initializeUI is not called for Firebug object since it has been already initialized, attachBrowser is called instead.


[edit] Shutdown

Firebug-shutdown-sequence.png

  • Entire shutdown process is triggered by unload event sent to Firebug object.
    • This is a bug to be fixed in the refactoring.
    • We need three window-unload operations: XUL window close, Firebug UI close, and application shutdown.
  • This diagram again shows that TabContext is not only responsible for managing web-page data, but also for Panel objects. TabContext creates and destroys all panels related to the current web-page/context.
  • Firebug object dispatches unwatchWindow to all Module objects. I think this is wrong, since modules shouldn't be tied to windows, do you agree?
    • this event means "detach any Firefox hooks you have related to a particular nsIDOMWindow"
  • If Firebug UI is detached, Firebug.shutdownFirebug calls also FirebugChrome.close, which consequently calls window.close.
  • There is additional shutdown process that calls Firebug.shutdown yet once. Is this OK? This process is triggered by initializer destructor, which is a binding associated with fbContentBox element. This element contains entire Firegug UI (except of the splitter).

Firebug-shutdown-sequence2.png

[edit] Close Firebug

[edit] Minimize Firebug

[edit] Enable Panel

Review of Firebug panel activation process, which must be refactored.

Firebug-enablepanel-sequence.png

  • Enable panel process starts from bindings.xml where Enabled and Disabled options are implemented as part of panelTabMenu.
  • The menu directly calls module.setDefaultState. This is wrong. The action should be dispatched to FirebugChrome object, which serves as a Controller for user commands. Consequently FirebugChrome gets the current panel (e.g. net), similarly to (and perhaps better) as it gets content for the panel file list (?), and ensures setting of net.enableSites preference. The target preference could be actually set by a Firebug.Activation object (activation.js) so, the activation code is concentrated at one place.
  • Since Firebug is observing nPref:changed events, it handles the pref change and dispatches onEnablePrefChange to all activable modules.
  • An activable module (e.g. net in this case) recognize the event (according to the pref name) and uses ModuleManager to dispatch further onPanelEnable to all activable modules. ModuleManager should be moved to activation.js and perhaps merged with Firebug.Activation.
  • ModuleManager causes UI update (panel tab is not gray anymore) and calls module.panelEnable for every context.
  • ActivableModule calls context.enablePanel and gives the panel an opportunity to show. This is wrong since the module uses associated panelName to get the right panel. The module shouldn't know anything about the panel (MVC pattern violation).
  • ActivableModule should not have methods onPanelEnable and panelEnable. This is panel specific.


  • The entire process is now simplified as follows.

Firebug-enablepanel-sequence-proposal.png

  • The user enables the Net panel. The panelBar object, which displays enable/disable menu items, calls setEnabled on the current panel type object (not on the panel instance, but on its prototype).
  • The panel type object (derived from Firebug.ActivablePanel) sets a preference to make the enablement persistent across Firefox sessions. The pref name is compounded also from panel's name (e.g. extensions.firebug.net.enableSites).
  • Firebug.PanelActivation observers the nsPref:change event and calls onActivationChanged, again on panel's type object.
  • The panel has an opportunity to register itself as an observer for specific modules. The Net panel adds itself as an observer of NetMonitor module.
  • onObserverChanged is executed on the module and it's also the place where the module should activate itself in case there are any observers or deactivate if there are no observers.
  • The main differences from the previous solution is that *it's the panel type* what is enabled/disabled. Module changes its state automatically upon existing observers (panels).
Firebug.ActivableModule = extend(Firebug.Module,
{
    addObserver: function(observer),
    removeObserver: function(observer),
    onObserverChange: function(observer)
}


Firebug.ActivablePanel = extend(Firebug.Module,
{
    isEnabled: function(),
    setEnabled: function(enable),
    onActivationChanged: function(enable)
}


Firebug.PanelActivation = extend(Firebug.Module,
{
    enablePanel: function(panel),
    disablePanel: function(panel),
    enableAllPanels: function(),
    disableAllPanels: function(),
}
Personal tools