Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Content Preferences - Architecture/API

7 views
Skip to first unread message

Myk Melez

unread,
Feb 14, 2007, 7:48:41 PM2/14/07
to
The content preferences code currently has a four piece architecture:

1. *a service* that manages the database of prefs;
2. *a controller* for each window that watches the browser's location
and notifies pref handlers when it changes;
3. *pref handlers* that tweak the browser according to the user's
prefs;
4. *a sidebar* housing controls for twiddling prefs.

In the first version of the extension, I designed these to support
preferences like the text zoom pref. In v2 I redesigned them to improve
that support and tried to generalize the API to work for other prefs.

But a single caller is a very limited perspective for designing an API
(indeed, I've already found issues while getting a second pref up and
running on it), so I'm keen to get feedback on how to make this work
well for other prefs (in both core code and extensions).

Here's how it works at the moment:


The Service (mozISitePrefService)

The service manages the database of prefs. Its API is pretty simple.
It has four core methods, getPref, setPref, hasPref, and removePref:

mozISitePref getPref(in AUTF8String site, in AUTF8String key);
void setPref(in AUTF8String site, in AUTF8String key,
in AUTF8String value);
boolean hasPref(in AUTF8String site, in AUTF8String key);
void removePref(in AUTF8String site, in AUTF8String key);


It also has a method, getPrefs, that gets all prefs for a site, and it
has another method, getSiteForURI, that extracts a site identifier from
a URI:

void getPrefs(in AUTF8String site,
out unsigned long prefCount,
[retval, array, size_is(prefCount)]
out mozISitePref prefs);

AUTF8String getSiteForURI(in nsIURI uri);


Site identifiers are full domains by default (f.e. www.mozilla.org), but
you can configure the extension to use base domains (f.e. mozilla.org),
and perhaps we'll cook up other options in the future.

The interface to a preference (mozISitePref) is very basic:

readonly attribute AUTF8String site;
readonly attribute AUTF8String key;
readonly attribute AUTF8String value;


The Controller (SitePref)

The controller's job is to notify pref handlers when the browser
location changes so those handlers can apply the user's preferences for
the new location. It has addObserver and removeObserver methods that
handlers can use to register/unregister themselves for notifications:

addObserver(in AUTF8String key, in nsISupports observer)
removeObserver(in AUTF8String key, in nsISupports observer)


The methods take a pref key so the controller knows what setting the
handler cares about. When the location changes, the controller grabs
the set of prefs for the new location and calls each observer's
onLocationChange method with the pref it cares about (if any):

onLocationChange(in nsISitePref pref)


The Pref Handlers

The pref handlers implement the aforementioned onLocationChange method
and then do whatever they need to do to apply user preferences to the
browser.


The Sidebar (chrome://cpref/content/sidebar.xul)

The sidebar provides a central location for site-specific preference
controls. It's an experiment in exposing these preferences in a place
that is location-specific (unlike the Preferences dialog) and visible
alongside the page being affected (unlike the View menu).

It doesn't do much besides provide a place for pref controls to overlay
themselves onto. Controls are responsible for updating themselves when
the location changes. But the sidebar does define a gMainWindow
shortcut for getting the browser window that the sidebar is embedded in.


Feedback

I'm interested in feedback on all aspects of this API. Here are the
questions I know I should ask:

1. Should pref values be typed?

We can't store them typed in the database given the EAV model
<http://en.wikipedia.org/wiki/Entity-Attribute-Value_model> we're
using to store them (although we could change the model if it
mattered enough), but we could convert them on their way in and
out of the database and have type-specific methods for getting and
setting them (à la nsIPrefBranch
<http://lxr.mozilla.org/mozilla/source/modules/libpref/public/nsIPrefBranch.idl>).

2. Should pref handlers listen for location changes themselves and
get their prefs directly from the service instead of having that
work be mediated by the controller?

It's faster for the controller to query once for all prefs, and
it's simpler on the pref handlers not to have to implement
nsIWebProgressListener
<http://lxr.mozilla.org/mozilla/source/uriloader/base/nsIWebProgressListener.idl>
themselves, but it makes the architecture more complex, since it
adds an extra layer between the service and the handlers.

3. Is AUTF8String the right string type for site identifiers and keys?

And then there are all those questions I don't know I should be asking
(along with their answers), so clue me in!

-myk

JP. Baker

unread,
Feb 15, 2007, 9:04:25 AM2/15/07
to
In article <p9-dnf0fOLFmME7Y...@mozilla.org>,

Myk Melez <m...@mozilla.org> wrote:
>The content preferences code currently has a four piece architecture:
>
> 1. *a service* that manages the database of prefs;
> 2. *a controller* for each window that watches the browser's location
> and notifies pref handlers when it changes;
> 3. *pref handlers* that tweak the browser according to the user's
> prefs;
> 4. *a sidebar* housing controls for twiddling prefs.
>
>In the first version of the extension, I designed these to support
>preferences like the text zoom pref. In v2 I redesigned them to improve
>that support and tried to generalize the API to work for other prefs.
>
>But a single caller is a very limited perspective for designing an API
>(indeed, I've already found issues while getting a second pref up and
>running on it), so I'm keen to get feedback on how to make this work
>well for other prefs (in both core code and extensions).
>
>...

I was actually thinking yesterday about how I could use this in my
extension and one thought that came to me is that in 99-100% of
cases there will be no value set for a sitepref and the code/extension
will use a default value; This would imply that having a controller makes
a lot of sense so that the observers only get told about keys that they
are interested in when they have a value. {later... except that they will
probably still need an onLocationChanged to know when to go back to the
default value; Or the observer will have to be told that the value is
finished with]

I suspect that various value types would be more useful but, in the case
under consideration, I want an (r, g, b) tuple so I would have to encode
it anyway.

It may be useful to have some fixed widgets (text, checkbox, select,
multiple select) that can be added to the sidebar and, together with
a pref key, would handle the sidebar display and store the preferences
without assistance; There could be a domain/host problem here as it may
not know which type of site is required.

sitepref.addTextPreference("addon.keyname", localisedstring,
sitepref.DOMAIN)
sitepref.addBooleanPreference("browser.option", localisedstring,
sitepref.SITE + sitepref.DEFAULTTRUE)
[later... on second thoughts there may be some validation required which
invalidates this method - but it may give the option of a better layout]

But the key point is to take into account how rarely a preference
will be set to a value compared with the number of sites visited.

John

--
John P Baker

Myk Melez

unread,
Feb 15, 2007, 5:39:17 PM2/15/07
to
JP. Baker wrote:

> I was actually thinking yesterday about how I could use this in my
> extension and one thought that came to me is that in 99-100% of
> cases there will be no value set for a sitepref and the code/extension
> will use a default value; This would imply that having a controller makes
> a lot of sense so that the observers only get told about keys that they
> are interested in when they have a value.

That's a good point, and it's probably true not only for your extension
but for many others (as well as core code which uses this facility).
Out of curiosity, which one is your extension?


> {later... except that they will
> probably still need an onLocationChanged to know when to go back to the
> default value; Or the observer will have to be told that the value is
> finished with]

Right, which is why the controller calls every handler when the location
changes instead of just those handlers for which there's a preference
for the new location.

But maybe there's a way to improve this by somehow making the controller
aware of the default values and thus able to tell when it needs to call
a handler to apply a different value (whether it's a default value or a
user preference).


> I suspect that various value types would be more useful but, in the case
> under consideration, I want an (r, g, b) tuple so I would have to encode
> it anyway.

You could use multiple preferences to store complex values (f.e. three
integer preferences for your tuple), although it might be easier to just
encode it.

nsIPrefBranch supports a "complex preference" type, which is defined as
"a preference which represents an XPCOM object that can not be easily
represented using a standard boolean, integer or string value."

But the implementation has to include explicit code to handle each
supported XPCOM interface (currently just nsILocalFile, nsIFileSpec,
nsISupportsString, and nsIPrefLocalizedString), and the values still get
encoded as strings, it's just that nsIPrefBranch is doing the encoding
on behalf of its callers.

Presumably this would only make sense for very common types, and its
unclear how frequently this is used or how useful it has proved to be.


> It may be useful to have some fixed widgets (text, checkbox, select,
> multiple select) that can be added to the sidebar and, together with
> a pref key, would handle the sidebar display and store the preferences
> without assistance; There could be a domain/host problem here as it may
> not know which type of site is required.

That's a good idea. Perhaps the basic functionality of most of these
widgets (presenting the options, saving them to the database when the
user changes them, and updating the value when it changes via some other
mechanism) works the same and thus could be factored out to make it
simpler for handlers to provide widgets for their prefs.

-myk

JP. Baker

unread,
Feb 16, 2007, 3:41:58 AM2/16/07
to
In article <p9-dnf0fOLFmME7Y...@mozilla.org>,
Myk Melez <m...@mozilla.org> wrote:
>
> The Sidebar (chrome://cpref/content/sidebar.xul)
>
>The sidebar provides a central location for site-specific preference
>controls. It's an experiment in exposing these preferences in a place
>that is location-specific (unlike the Preferences dialog) and visible
>alongside the page being affected (unlike the View menu).
>
>It doesn't do much besides provide a place for pref controls to overlay
>themselves onto. Controls are responsible for updating themselves when
>the location changes. But the sidebar does define a gMainWindow
>shortcut for getting the browser window that the sidebar is embedded in.

Presumably you would want all site preferences to be shown here? It sounds
expensive for ten or twenty widgets to update themselves on every location
change; All consumers will probably end up watching for sidebar opening
and closing to see if their widget was hidden or not. (A boolean method
on the service won't be enough as it wouldn't catch the first site when
the sidebar was opened)

It may be worth considering splitting the prefs controller and providing
a separate "The sidebar is open and the _site_ has changed so please
update your widget" observer topic.

In addition to a setting each pref will need a "use default setting" checkbox
(preferably unchecked means default), eg "enable javascript" would need True,
False and "Use global setting"; This box should be consistent for all the
widgets so the configuration is unified. The end result would be something
like the (bottom of the) "Connection Settings" preference box - but with more
fieldsets. Clearing the checkbox would mean delete (remove) the site
preference.

JP. Baker

unread,
Feb 16, 2007, 4:01:45 AM2/16/07
to
In article <V4Wdnc6h4qOKfEnY...@mozilla.org>,

Myk Melez <m...@mozilla.org> wrote:
>That's a good point, and it's probably true not only for your extension
>but for many others (as well as core code which uses this facility).
>Out of curiosity, which one is your extension?

The extension is HashColouredTabs+ (every third comment in HashColouredTabs,
Chromatabs, and others, seems to be a request to allow setting the colour for
a host or domain). Some of my other comments aren't particularly relevant
to this extension as I would certainly be calling getPref rather than using
observers as the pref is for a default colour if there isn't a site-icon or
favicon:

host = browser.webNavigation.currentURI.host;
if (host.length == 0) throw "host = empty string";
} catch (e) {
host = browser.webNavigation.currentURI.scheme;
}
var rgb = this.getHashColorForTab(host);

so it would try to get rgb from the site preferences before getting a random
one.

[There is also a possibility that I will be able to use the Favicon/History
services instead - this may depend on how the history sidebar shows and stores
site _folder_ icons]


--
John P Baker

JP. Baker

unread,
Feb 16, 2007, 10:45:11 AM2/16/07
to
In article <sKCdnSUiJ8jL80jY...@mozilla.org>,

JP. Baker <John.P...@bristol.ac.uk> wrote:
>In addition to a setting each pref will need a "use default setting" checkbox
>(preferably unchecked means default), eg "enable javascript" would need True,
>False and "Use global setting"; This box should be consistent for all the
>widgets so the configuration is unified. The end result would be something
>like the (bottom of the) "Connection Settings" preference box - but with more
>fieldsets. Clearing the checkbox would mean delete (remove) the site
>preference.

Oops! I also meant to mention greying-out the widget when a site was using
the default value rather than a value from the database.

Myk Melez

unread,
Feb 16, 2007, 3:19:18 PM2/16/07
to
JP. Baker wrote:

> Presumably you would want all site preferences to be shown here?

That's the idea, but it's just experimental at this point. We may find
that existing UI (like the View menu and the Preferences dialog) are
sufficient or preferable to a sidebar.

Or perhaps there's something else we could do that would be even better.
For example, there's been some work to add site-specific settings to
the Page Info dialog, although that seems a bit out of the way to me
(but we could make that dialog a sidebar, which I think we should do
anyway).


> It sounds expensive for ten or twenty widgets to update themselves
> on every location change;

It's unclear how expensive it'd be to update 10-20 widgets. My guess is
that it would be reasonable, especially for a sidebar that isn't open
most of the time, but I guess there's only one way to find out. :-)

(I'm actually more worried about querying the database 10-20 times,
which could hit the disk repeatedly, than twiddling the widgets, which
is why I'm having the controller grab all prefs once per site and then
dole them out to each handler).


> All consumers will probably end up watching
> for sidebar opening and closing to see if their widget was hidden
> or not. (A boolean method on the service won't be enough as it
> wouldn't catch the first site when the sidebar was opened)

Currently, the widgets ping the handlers for an initial value when the
sidebar opens, which takes care of the "first site when the sidebar was
opened" problem. But each widget is responsible for issuing this ping,
which seems suboptimal.

Afterwards, when a site changes, the handlers check to see if the
sidebar is open via document.getElementById, which is probably pretty
efficient, but perhaps it would make sense to move that check into a
boolean property on the controller, so handlers have an easy-to-remember
API method for that common operation.

Note that we'd want to put that on the controller instead of the service
because the service isn't window-specific, while the sidebar is, so its
state could vary from window to window.


> It may be worth considering splitting the prefs controller and providing
> a separate "The sidebar is open and the _site_ has changed so please
> update your widget" observer topic.

Yeah, I've been thinking about how the observer service could be
productively used to notify handlers that the site has changed. I'm
trying to avoid making each handler hit the database directly, since
that seems like it could be a performance hit.

Perhaps the subject of the notification could be a hash of preferences
the controller has retrieved from the database, and the handlers could
grab their preferences from the hash.

In any case, notifying observers when the sidebar opens seems like a
great way to obviate the need for each widget to ping its handler.


> In addition to a setting each pref will need a "use default setting"
> checkbox (preferably unchecked means default), eg "enable javascript"
> would need True, False and "Use global setting"; This box should be
> consistent for all the widgets so the configuration is unified.

Yeah, we definitely need a way for a user to say "use the default
setting" (and also a way for the user to set the default setting). And
you're right that it should be consistent across widgets.

I'm not sure this is necessarily a checkbox for every widget, however.
That seems like an awful lot of additional UI complexity in a sidebar
that may end up being fairly dense. I'm hoping for some UE inspiration
to strike. :-)


> The end result would be something like the (bottom of the)
> "Connection Settings" preference box - but with more fieldsets.
> Clearing the checkbox would mean delete (remove) the site
> preference.

I think I'm missing something here, as I don't see something at the
bottom of that dialog that seems pertinent to your description of the
default checkbox functionality.

-myk

Myk Melez

unread,
Feb 16, 2007, 3:29:34 PM2/16/07
to
JP. Baker wrote:

> The extension is HashColouredTabs+ (every third comment in HashColouredTabs,
> Chromatabs, and others, seems to be a request to allow setting the colour for
> a host or domain). Some of my other comments aren't particularly relevant
> to this extension as I would certainly be calling getPref rather than using
> observers as the pref is for a default colour if there isn't a site-icon or
> favicon:

Hmm, I guess I don't understand how you'd need to call getPref here
instead of using an observer.


> host = browser.webNavigation.currentURI.host;
> if (host.length == 0) throw "host = empty string";
> } catch (e) {
> host = browser.webNavigation.currentURI.scheme;
> }

Interesting idea using the scheme as the "site" if the URI doesn't have
a host property. I wonder if that would make sense for site-specific
preferences generally.

-myk

John P Baker

unread,
Feb 16, 2007, 4:49:48 PM2/16/07
to
In message <ZKmdnQEQPZGoiUvY...@mozilla.org>
Myk Melez <m...@mozilla.org> wrote:

> JP. Baker wrote:
>
> > The extension is HashColouredTabs+ (every third comment in HashColouredTabs,
> > Chromatabs, and others, seems to be a request to allow setting the colour for
> > a host or domain). Some of my other comments aren't particularly relevant
> > to this extension as I would certainly be calling getPref rather than using
> > observers as the pref is for a default colour if there isn't a site-icon or
> > favicon:
>
> Hmm, I guess I don't understand how you'd need to call getPref here
> instead of using an observer.

Well, originally, I meant because I won't need it very often as most sites have a
site icon or favicon that will be used instead of falling back to the site
preference; But also, now I think about it, I will quite often want the preference
for a background tab which, presumably, won't cause the appropriate events until
selected [I'll have to read up on this to be sure]

--
John P Baker

John P Baker

unread,
Feb 17, 2007, 2:25:48 PM2/17/07
to
In message <V4Wdnc6h4qOKfEnY...@mozilla.org>
Myk Melez <m...@mozilla.org> wrote:

> JP. Baker wrote:
>
> > I was actually thinking yesterday about how I could use this in my
> > extension and one thought that came to me is that in 99-100% of
> > cases there will be no value set for a sitepref and the code/extension
> > will use a default value; This would imply that having a controller makes
> > a lot of sense so that the observers only get told about keys that they
> > are interested in when they have a value.
>
> That's a good point, and it's probably true not only for your extension
> but for many others (as well as core code which uses this facility).

I've been doing some back-of-the-envelope calculations that make me wonder if
we need the controller for this rather than just letting consumers call getPref
when they want a value:

o Assume that we have a good hashing algorithm for hosts - ISTR an enhancement
request for one but I don't know if it ever got written - producing around 1000
values.
o Assume that the user has more than 20, but less than 100, sites with preferences
set.

o We can have a 128 byte bit map indicating if that hash has any entries in the
database. More than 90% of sites can now immediately return 'default' for a call
of getPref.
o Cache the results of the last 2 or 3 database queries. Most getPref's will want a
pref for the current location.

...

--
John P Baker

JP. Baker

unread,
Feb 20, 2007, 9:57:36 AM2/20/07
to

OK, I now have an experimental implementation for HashColouredTabs+ and, in
fact, it seems that most of my concerns were already addressed by your
proposal. What I have is:

o I use getPref when I want an RGB value as (a) I don't need one very often and
(b) it will often be for a background tab.
o I have both a 'load' and 'unload' listener for the sidebar which means that I
only monitor locationChange when the sidebar window is open; This location
change updates the control to the current value.
o I only have a simple widget at the moment so I can use a null string to
represent no value in database and to delete a value that is already in it.

The WIP version is at
http://seis.bris.ac.uk/~ccjpb/hashcolouredtabs0491.xpi
although I intend to review it tonight.

Presumably you have seen the Storage Inspector extension which is very useful
for tasks like this:
https://addons.mozilla.org/firefox/3072/

One question - Do I have to worry about the order of the extensions loading?
Obviously I want to be able to run without 'Content Preferences' but I do
need to overlay the sidebar if it is present, and I am not quite sure of the
mechanism that this uses.

Myk Melez

unread,
Feb 20, 2007, 8:20:39 PM2/20/07
to
John P Baker wrote:

> Well, originally, I meant because I won't need it very often as most sites
> have a site icon or favicon that will be used instead of falling back
> to the site preference;

Ah, I see. So most of the time you don't need to check the pref when
the location changes. Right, it makes sense to use getPref directly in
that circumstance.


> But also, now I think about it, I will quite often want the preference
> for a background tab which, presumably, won't cause the appropriate events until
> selected [I'll have to read up on this to be sure]

Yup, that's correct. The controller just notifies preference handlers
about a change to the "current" location in the foreground tab.

-myk

Myk Melez

unread,
Feb 20, 2007, 8:21:32 PM2/20/07
to
John P Baker wrote:

> o We can have a 128 byte bit map indicating if that hash has any entries in the
> database. More than 90% of sites can now immediately return 'default' for a call
> of getPref.
> o Cache the results of the last 2 or 3 database queries. Most getPref's will want a
> pref for the current location.

Sounds like that would indeed minimize the database cost. It wouldn't
improve the XPCOM method call cost, however (not sure how significant
this is).

But perhaps I'm optimizing prematurely and should opt for a simpler
implementation without the controller until experience demonstrates its
value (for performance or to make writing handlers easier).

-myk

Myk Melez

unread,
Feb 20, 2007, 10:03:46 PM2/20/07
to
JP. Baker wrote:
> OK, I now have an experimental implementation for HashColouredTabs+ and, in
> fact, it seems that most of my concerns were already addressed by your
> proposal. What I have is:
>
> o I use getPref when I want an RGB value as (a) I don't need one very often and
> (b) it will often be for a background tab.

Yup, that sounds like the right approach.


> o I have both a 'load' and 'unload' listener for the sidebar which means that I
> only monitor locationChange when the sidebar window is open; This location
> change updates the control to the current value.

This seems fine. I wonder if we can make it easier for handlers to
watch the sidebar, but perhaps load and unload listeners are already
simple enough.


> o I only have a simple widget at the moment so I can use a null string to
> represent no value in database and to delete a value that is already in it.

That seems reasonable. It sounds like you're taking advantage of the
fact that getPref doesn't distinguish between "doesn't have a record in
the database" and "has a record in the database whose value is null".

I wonder if it would make sense to distinguish between those two cases.


> The WIP version is at
> http://seis.bris.ac.uk/~ccjpb/hashcolouredtabs0491.xpi
> although I intend to review it tonight.

I tried it out, and the control appears in the sidebar just fine. It
didn't take effect immediately when I set a color preference for a site,
but the pref took effect once I reloaded the page.


> Presumably you have seen the Storage Inspector extension which is very useful
> for tasks like this:
> https://addons.mozilla.org/firefox/3072/

Yup. Last time I tried it, it didn't work for some databases, but it
looks like it works fine with the content prefs database. Excellent!


> One question - Do I have to worry about the order of the extensions loading?
> Obviously I want to be able to run without 'Content Preferences' but I do
> need to overlay the sidebar if it is present, and I am not quite sure of the
> mechanism that this uses.

There are two questions: what happens when the content preferences
extension and some other dependent extension are both installed, but the
dependent extension gets loaded first, and what happens when only the
dependent extension is installed.

Regarding the first question, I think the sidebar doesn't get opened
until after the overlay info for all extensions has already been loaded,
in which case the order in which extensions get loaded doesn't matter
for the dependent extension's sidebar overlay.

It could matter for accessing the site prefs service, however, if the
dependent extension does so in a component, and the service's component
hasn't been loaded yet.

But that's a known issue with components generally, not something
specific to this one, and it's generally resolved by delaying the use of
components (or not relying on their availability) until all component
loading is done.

I think this is why the update service adds an entry to the
"app-startup" category:

http://lxr.mozilla.org/mozilla/source/toolkit/mozapps/update/src/nsUpdateService.js.in#2849

And the microsummary service handles this by delaying initialization
until its factory gets called to instantiate it:

http://lxr.mozilla.org/mozilla/source/browser/components/microsummaries/src/nsMicrosummaryService.js#2435

Regarding the second question, I've done some testing, and it doesn't
appear to cause problems when the dependent extension tries to overlay a
nonexistent sidebar. The following message appears on the Error Console:

No chrome package registered for chrome://cpref/locale/sidebar.dtd .

But there appear to be no ill effects. Other code provided by the
dependent extension (f.e. an overlay onto browser.xul) gets loaded and
executed just fine.

The dependent extension needs to test for the presence of the content
preferences code before trying to use it, of course. Depending on what
it uses, it could check for the controller or the service (or both):

if (typeof SitePref == "undefined") {
// no controller
}

var sitePrefsSvc;
try {
sitePrefsSvc =
Components.classes["@mozilla.org/site-pref/service;1"].
getService(Components.interfaces.nsISitePrefService);
}
catch(ex) {
// no service
}

-myk

JP. Baker

unread,
Feb 21, 2007, 3:37:27 AM2/21/07
to
In article <p9-dnf0fOLFmME7Y...@mozilla.org>,
Myk Melez <m...@mozilla.org> wrote:
> The Controller (SitePref)
>
>The controller's job is to notify pref handlers when the browser
>location changes so those handlers can apply the user's preferences for
>the new location. It has addObserver and removeObserver methods that
>handlers can use to register/unregister themselves for notifications:
>
>addObserver(in AUTF8String key, in nsISupports observer)
>removeObserver(in AUTF8String key, in nsISupports observer)
>
>
>The methods take a pref key so the controller knows what setting the
>handler cares about. When the location changes, the controller grabs
>the set of prefs for the new location and calls each observer's
>onLocationChange method with the pref it cares about (if any):
>
>onLocationChange(in nsISitePref pref)

On reflection, I suspect that this is not quite right; I expected to
add a 'proper' observer with a topic (even if there is only one at the
moment) and for the observer call to be

observe(subject, topic, pref)

which, for me, is already observing 'nsPref:changed' and
'em-action-requested'; This change would also allow you to add more topics
later if required.

john
--
John P Baker

JP. Baker

unread,
Feb 21, 2007, 3:42:06 AM2/21/07
to
In article <cKOdnYQndLkBA0bY...@mozilla.org>,

Myk Melez <m...@mozilla.org> wrote:
>
>But perhaps I'm optimizing prematurely and should opt for a simpler
>implementation without the controller until experience demonstrates its
>value (for performance or to make writing handlers easier).
>

I am definitely coming round to the controller; As I said elsewhere, I
found that I can enable it when required (when the prefs window is open)
and I think I had overlooked the complexity of needing the unset prefs
as well as the set prefs..

JP. Baker

unread,
Feb 21, 2007, 4:02:37 AM2/21/07
to
In article <z9idnQUCEOAMK0bY...@mozilla.org>,
Myk Melez <m...@mozilla.org> wrote:

>JP. Baker wrote:
>> o I only have a simple widget at the moment so I can use a null string to
>> represent no value in database and to delete a value that is already in
>> it.
>
>That seems reasonable. It sounds like you're taking advantage of the
>fact that getPref doesn't distinguish between "doesn't have a record in
>the database" and "has a record in the database whose value is null".
>
>I wonder if it would make sense to distinguish between those two cases.

This is fine for my case it is only ever'RRGGBB'; I still suspect that
we really need a checkbox for saying a site is using the default value and
to delete it if necessary. One thing I have noticed is that, if we need to
use groupboxes, and I suspect we will, that you are allowed one in the
caption which may work. See example 3.4.2 in

http://www.xulplanet.com/tutorials/xultu/titledbox.html

This is what I was trying to say when I mentioned a consistent layout (and
possibly even checkboxes for every setting)

Myk Melez

unread,
Feb 21, 2007, 7:08:16 PM2/21/07
to

The problem with using "proper" observers via the observer service is
that the observer service can't be used to send customized notifications
that contain each handler's own prefs. It can only be used to broadcast
the same notification to all handlers observing a given topic (f.e.
"current-site-changed").

Of course, we could have handlers query the controller for their prefs
when they receive the notification. Or we could pass a reference to a
hash of all prefs in the notification itself.

And there are other advantages to using "proper" observers, as you note,
like extensions being able to reuse their existing infrastructure for
observing notifications and the controller being able to reuse its
existing infrastructure for sending them.

So here's what an interface like that might look like:

When the browser window loads, pref handlers call
nsIObserverService::addObserver to register themselves as observers of
the "current-site-changed" topic.

Then, when the current site changes, the controller calls
nsIObserverService::notifyObservers with the "current-site-changed"
topic, the site identifier as the data parameter, and a hash of prefs
(indexed by pref identifier) as the subject parameter. Handlers
retrieve their prefs from the hash and apply them as they see fit.

Alternately, the subject parameter contains a reference to the current
browser (or an object composed of the browser and a hash of its prefs),
and preferences query the controller for their preferences.

One advantage of passing a reference to the current browser is
consistency with a "site-changed" notification, if we were to implement
one for site changes in a non-current tab, since for that notification
we would have to indicate the browser whose site had changed.

-myk

Alex Faaborg

unread,
Feb 22, 2007, 6:54:40 PM2/22/07
to Myk Melez, dev-apps...@lists.mozilla.org, Mike Beltzner
> I'm not sure this is necessarily a checkbox for every widget,
> however. That seems like an awful lot of additional UI complexity
> in a sidebar that may end up being fairly dense. I'm hoping for
> some UE inspiration to strike. :-)

If you post a list of the controls you want in the sidebar, I can get
a better sense of how to streamline the UI. In general, checkboxes
that had two states now need to have three (true, false,
Normal:Value), so they probably should turn into menulists (as
opposed to radio buttons). Sliders should gain a default checkbox
that sets the slider value to the default and then disables it.
Menulits would just gain an extra option.

If you want to start rolling your own widgets, sliders could have a
tick mark that shows the default value, and the user can set it back
to the default value by moving the control to the tick mark (which
would hopefully be a little sticky).

We probably need a better word than "default" for the uI maybe "Normal"?

-Alex

> _______________________________________________
> dev-apps-firefox mailing list
> dev-apps...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-apps-firefox

Myk Melez

unread,
Feb 22, 2007, 9:46:15 PM2/22/07
to Alex Faaborg, Mike Beltzner
Alex Faaborg wrote:
> If you post a list of the controls you want in the sidebar, I can get a
> better sense of how to streamline the UI.

In theory, a number of our content settings would work better as
site-specific settings. But it's hard to make decisions about which
ones to include in a site-specific sidebar, because after reviewing the
ones currently in Firefox, I have come to the conclusion that our entire
approach to content settings needs a revamp.

Right now our settings tend to focus on specific technologies. For
example, we have a "page style" setting for selecting between
alternative CSS stylesheets and an "enable JavaScript" option for
enabling/disabling the execution of scripts in that language.

But only techies know what JavaScript is or when it might be useful to
disable it. And I can't think of much use for the "page style" setting,
since virtually no sites employ alternative stylesheets (except possibly
for the setting's "no style" option, if that makes some sites more
readable).

The situation seems the same in extensionland, where Flashblock targets
a specific technology (Flash animations) rather than the problem with
that technology (annoying/distracting motion), which can be created by a
number of technologies.

In general, rather than providing settings to enable/disable specific
technologies, I think we should focus on what users want to be able to
do with a site, based on their mental model, and then create settings
that allow them to do those things.

For example, users might want to "freeze" or "pause" a page, which could
involve stopping the execution of JavaScript (or perhaps just DOM/CSS
manipulations), pausing Flash and animated GIFs, and otherwise ensuring
that the stuff in the page stops changing position/appearance.

Users might also want to "mute" a page or site so that it doesn't make
sound. And they might want to see a "text only - no graphics" version
of a site, which could mean disabling images, plugins, and some CSS style.

Not all desired user manipulations should end up with settings, of
course. We should apply our usual standards, which means that some will
be more appropriate as extensions (or won't be appropriate at all).

And we could always move our technology-specific settings into the
site-specific sidebar and then work on improving their utility along the
lines outlined above.

But it's hard to imagine a sidebar with "enable JavaScript", "page
style", "enable Java" and "load images" being what we ultimately want,
so whatever order we do it in, I think we need to figure out what
settings actually make sense for our broad userbase in order for a
content settings sidebar to make any sense in our product.

-myk

Message has been deleted

Myk Melez

unread,
Feb 22, 2007, 9:48:03 PM2/22/07
to Alex Faaborg, Mike Beltzner
Alex Faaborg wrote:
> If you post a list of the controls you want in the sidebar, I can get a
> better sense of how to streamline the UI.

In theory, a number of our content settings would work better as

site-specific content settings sidebar (or the like) to make any sense
in our product.

-myk

JP. Baker

unread,
Feb 23, 2007, 5:10:02 AM2/23/07
to
In article <z9idnQUCEOAMK0bY...@mozilla.org>,
Myk Melez <m...@mozilla.org> wrote:

>JP. Baker wrote:
>> One question - Do I have to worry about the order of the extensions loading?
>> Obviously I want to be able to run without 'Content Preferences' but I do
>> need to overlay the sidebar if it is present, and I am not quite sure of the
>> mechanism that this uses.
>
>There are two questions: what happens when the content preferences
>extension and some other dependent extension are both installed, but the
>dependent extension gets loaded first, and what happens when only the
>dependent extension is installed.
>
>Regarding the first question, I think the sidebar doesn't get opened
>until after the overlay info for all extensions has already been loaded,
>in which case the order in which extensions get loaded doesn't matter
>for the dependent extension's sidebar overlay.

Having tried this a couple of times, I think I would suggest that you make
your text-zoom use a position

<hbox id="text.zoom-pref" align="center" position="1">

as it means that browser preferences can come before other extension
preferences; I can't see an easy way to force my preferences to come after - I
could, for now, use insertafter but, once you add some more, I can't use it
reliably.

Myk Melez

unread,
Feb 23, 2007, 7:37:00 PM2/23/07
to Alex Faaborg, Mike Beltzner
Alex Faaborg wrote:
> In general, checkboxes that
> had two states now need to have three (true, false, Normal:Value), so
> they probably should turn into menulists (as opposed to radio buttons).
> Sliders should gain a default checkbox that sets the slider value to the
> default and then disables it. Menulits would just gain an extra option.

Yeah, I realize I need to support resetting a value to the default.
I've just been hoping for some inspiration to provide a better mechanism
than adding a checkbox to every item or turning checkboxes into menulists.


> If you want to start rolling your own widgets, sliders could have a tick
> mark that shows the default value, and the user can set it back to the
> default value by moving the control to the tick mark (which would
> hopefully be a little sticky).

I'm willing to roll my own widgets if necessary (or modify them, as in
the case of the slider).


> We probably need a better word than "default" for the uI maybe "Normal"?

Sounds good to me!

-myk

Myk Melez

unread,
Feb 23, 2007, 7:39:35 PM2/23/07
to
JP. Baker wrote:
> Having tried this a couple of times, I think I would suggest that you make
> your text-zoom use a position
>
> <hbox id="text.zoom-pref" align="center" position="1">
>
> as it means that browser preferences can come before other extension
> preferences; I can't see an easy way to force my preferences to come after - I
> could, for now, use insertafter but, once you add some more, I can't use it
> reliably.

Perhaps it would make sense to add an invisible element at the end of
the standard browser controls so that extensions could consistently add
their controls after the browser controls.

-myk

Jesper Kristensen

unread,
Feb 24, 2007, 8:09:13 AM2/24/07
to
Alex Faaborg wrote:
> If you post a list of the controls you want in the sidebar, I can get a
> better sense of how to streamline the UI. In general, checkboxes that
> had two states now need to have three (true, false, Normal:Value), so
> they probably should turn into menulists (as opposed to radio buttons).
> Sliders should gain a default checkbox that sets the slider value to the
> default and then disables it. Menulits would just gain an extra option.

I don't see the need for a third value for checkboxes. If the default is
unchecked and the user unchecks the checkbox, it would be equal to
setting the value to "default". However some UI indicating if the
current value is default or not might be useful (like what bold lines in
about:config does).

Instead of giving meulists an extra option, you could just append
something like "(default)" to the existing default option.

Myk wrote:
> Right now our settings tend to focus on specific technologies. For example, we have a "page style" setting for selecting between alternative CSS stylesheets and an "enable JavaScript" option for enabling/disabling the execution of scripts in that language.

Everything I can think of (cookies, images, text zoom, pop-ups, link
behavior) seems somewhat technical to me. Actually I don't think many
non techey users would ever try to edit site specific preferenes no
matter what they are. This feature would mostly target technically
experienced users, that knows something about what cookies and
JavaScript does.

BTW, how should these prefs show up in about:config? Is it planned to
allow hidden prefs to be site specific?

John P Baker

unread,
Feb 24, 2007, 10:06:07 AM2/24/07
to
In message <h_CdnUTz0eNkpX3Y...@mozilla.org>
Jesper Kristensen <bl...@blah.com> wrote:

> Alex Faaborg wrote:
> > If you post a list of the controls you want in the sidebar, I can get a
> > better sense of how to streamline the UI. In general, checkboxes that
> > had two states now need to have three (true, false, Normal:Value), so
> > they probably should turn into menulists (as opposed to radio buttons).
> > Sliders should gain a default checkbox that sets the slider value to the
> > default and then disables it. Menulits would just gain an extra option.
>
> I don't see the need for a third value for checkboxes. If the default is
> unchecked and the user unchecks the checkbox, it would be equal to
> setting the value to "default". However some UI indicating if the
> current value is default or not might be useful (like what bold lines in
> about:config does).

Taking "allow scripting" as an example - You want "never run script", "always
run script" and "follow the global pref setting", this third option would
delete the site-specific preference. You don't want a change in the global
setting to suddenly allow/stop a dis/trusted site from working as you require.
--
John P Baker

John P Baker

unread,
Feb 25, 2007, 3:02:05 AM2/25/07
to
In message <45DF88AC...@mozilla.org>
Myk Melez <m...@mozilla.org> wrote:

> Alex Faaborg wrote:
> > In general, checkboxes that
> > had two states now need to have three (true, false, Normal:Value), so
> > they probably should turn into menulists (as opposed to radio buttons).
> > Sliders should gain a default checkbox that sets the slider value to the
> > default and then disables it. Menulits would just gain an extra option.
>
> Yeah, I realize I need to support resetting a value to the default.
> I've just been hoping for some inspiration to provide a better mechanism
> than adding a checkbox to every item or turning checkboxes into menulists.

You may be able to use a button that rotates through the values

label: [B] |Current Value|

(which may also work with tri-value selections
image animation: [B] |Yes/No/Once/_Use global_|
)

or even

label: [B] [Select list]

For my RGB selector, I am currently using all sliders on their 'home' (min)
position to mean default; But, unlike the text-size, I do not need to start
the slider at the current value. [It does also mean that I can't set 'black'
but that seems a small price - there is always #010101]

> > We probably need a better word than "default" for the uI maybe "Normal"?
>
> Sounds good to me!

This may vary anyway, eg for sticky alternate stylesheets [1] the choice may be
preferredTitle/AlternateTitle1/AlternateTitle2/.../_use preferred_

The accessibility issue for any of this could be a nightmare - Tab/ShiftTab
works now - but how to assign accesskeys. [2]

[1] Site preferences may be too coarse to actually use for this
[2] I notice that the slider doesn't seem to have a focussed state! I might
expect that its label would gain a focus ring.

--
John P Baker

Dan Mosedale

unread,
Mar 1, 2007, 4:24:29 PM3/1/07
to
Myk Melez wrote:
>
> In theory, a number of our content settings would work better as
> site-specific settings. But it's hard to make decisions about which
> ones to include in a site-specific sidebar, because after reviewing the
> ones currently in Firefox, I have come to the conclusion that our entire
> approach to content settings needs a revamp.
>
> Right now our settings tend to focus on specific technologies. For
> example, we have a "page style" setting for selecting between
> alternative CSS stylesheets and an "enable JavaScript" option for
> enabling/disabling the execution of scripts in that language.
>
> But only techies know what JavaScript is or when it might be useful to
> disable it. And I can't think of much use for the "page style" setting,
> since virtually no sites employ alternative stylesheets (except possibly
> for the setting's "no style" option, if that makes some sites more
> readable).

This sure feels right to me. I can't imagine (for example) my parents
ever having any idea of when it would make sense to use these settings,
so they currently just act as extra UI clutter.

> In general, rather than providing settings to enable/disable specific
> technologies, I think we should focus on what users want to be able to
> do with a site, based on their mental model, and then create settings
> that allow them to do those things.

This definitely seems more sensible than the current jumble.

Dan

0 new messages