Site-Specific Preferences: Difference between revisions

Jump to navigation Jump to search
document the service API
(document the service API)
Line 121: Line 121:
== API Changes ==
== API Changes ==


This feature changes no existing APIs, but it does add several APIs.  First, it adds a application-wide API for getting and setting site-specific preferences.  Second, it adds a window-specific API for registering as a site-specific pref handler and observing preference-related events.  Third, it adds an API (in the form of structured UI) for presenting the user with controls for viewing and modifying site-specific prefs.
This feature changes no existing APIs, but it does add several APIs.  First, it adds a application-wide "service" API for getting and setting site-specific preferences.  Second, it adds a window-specific "controller" API for registering as a pref handler and observing pref-related events.  Third, it adds a "sidebar" API for adding controls to a sidebar presenting a consolidated view of preferences for the current site.
 
=== Service API ===
 
The service is implemented as a JavaScript XPCOM component with contract ID "@mozilla.org/content-pref/service;1" that implements the nsIContentPrefService interface.
 
==== Core Methods ====
 
The service's core API comprises the following four methods:
  nsIVariant getPref(in nsIURI uri, in AString name);
  void setPref(in nsIURI uri, in AString name, in nsIVariant value);
  boolean hasPref(in nsIURI uri, in AString name);
  void removePref(in nsIURI uri, in AString name);
 
All four methods take as input a URI belonging to the site in question and a name for the preference.  The service is responsible for extracting the name of the site from the URI.
 
Question: should we make the consumer responsible for extracting site names from URIs so consumers can set preferences for non-standard groupings?
 
The name of the preference is an arbitrary string.  Preference namespacing is the responsibility of the consumer, as it is with the application-wide preferences accessed via nsIPrefBranch.
 
The setPref method also takes as input an nsIVariant representing the value of the preference, while the getPref method returns such an nsIVariant.  Consumers can set the value of a preference to null (nsIVariant::VTYPE_EMPTY), and the service distinguishes between preferences set to null and those that have not been set by representing the latter as the undefined value (nsIVariant::VTYPE_VOID).
 
==== Getting All Prefs ====
 
The getPrefs method allows consumers to retrieve all preferences for a given site:
 
  nsIPropertyBag getPrefs(in nsIURI uri);
 
The method returns an instance of "@mozilla.org/hash-property-bag;1", which implements both the nsIPropertyBag and the nsIPropertyBag2 interfaces.  Bag keys are preference names, while bag values are preference values.
 
==== Observers ====
 
The service also implements methods for adding and removing observers:
 
  void addObserver(in AString name, in nsIObserver observer, in boolean holdWeak);
  void removeObserver(in AString name, in nsIObserver observer);
 
When a pref changes, the service notifies observers via the "content-pref-changed" topic.  The notification is similar to one nsIPrefBranch2 sends with the "nsPref:changed" topic, but it has two key differences:
 
* nsIContentPrefService takes only an exact preference name (nsIPrefBranch2 permits a consumer to watch an entire preference branch by passing in a branch prefix like "foo.bar.")
* nsIContentPrefService passes the new value of the pref in notification's subject parameter, which is an nsIPropertyBag containing the following properties:
** group: the site (or other grouping) to which the preference belongs;
** name: the name of the preference;
** oldValue: the old value of the preference;
** newValue: the new value of the preference.
 
Question: should the service support preference branches?
 
Question: should the service pass a custom component with a custom interface (like the LiveTitleNotificationSubject component with the nsILiveTitleNotificationSubject interface) instead of a property bag?
 
Question: is there any use for the notification's data parameter?
 
==== Groupers ====
 
Finally, the service implements an attribute representing the grouper (i.e. the component implementing the nsIContentURIGrouper interface, about which see below) that the service uses to extract a site from a URI:
 
  attribute nsIContentURIGrouper grouper;
 
The attribute is read/write so that extensions can change the grouper (and thus the way the service groups URIs).
 
Question: would make more sense for this to be read-only and for the service to set the value of the attribute to the grouper specified by an application-wide preference?
 
Groupers are components that categorize URIs into groups (f.e. by site).  They implement a simple interface, nsIContentURIGrouper:
 
    readonly attribute AString name;
    AString group(in nsIURI uri);
 
The name attribute is an arbitrary identifier for the grouper that the service uses to associate a preference in the database with the grouper responsible for determining its group.  The group method returns the name of the group to which a given URI belongs.
 
Question: should we just use the contract ID as the arbitrary identifier for the grouper, and how do we retrieve that from an instance of the component?
 
The default grouper categorizes URIs by effective TLD + one additional hostname segment (i.e. example.com or bbc.co.uk).
 
Question: should the default grouper categorize URIs by entire hostname?
 
The service distinguishes between groups with the same name that have been categorized by different groupers to avoid collisions between groups that have the same name but are semantically different.
 
Question: should we make groupers responsible for namespacing group names to avoid these collisions by the same way we make pref consumers responsible for namespacing pref names?


== Extensibility ==
== Extensibility ==
canmove, Confirmed users
2,056

edits

Navigation menu