I encountered the following problem: Change font and color for XUL tree based on user input. The user chooses the font and picks the color from a dialog and the tree widget is immediately redrawn with the new styles.
Changing styles for XUL trees requires the implementation of a nsITreeView, some nsIAtomService manipulation and some Mozilla CSS Extensions, definitively a bit verbose but enough simple after a dozen of attempts
.
The Mozilla CSS tree extensions are mainly pseudo-classes that can’t be modified from code, so you need to create a CSS text snippet with new values and then “reload” it.
Reloading CSS files can be accomplished using the nsIStyleSheetService service, it only requires a nsIURI pointing to the CSS resource.
Based on the scenario described above the styles are generated at runtime so I need to create a CSS style representation and stores it for example on a temp file. The styles don’t really need to be persisted on disk so why do I need to create an unuseful file?
Well using the “data:” protocol it is possible to encode the generated CSS string and pass to nsIURI the data uri without needs to create temporary files as shown below.
function applyUserStyles(cssStyles) {
// myTreeChildren is the CSS class name used for the tree
// obviously can be parametrized
var css = '.myTreeChildren::-moz-tree-cell-text {' + cssStyles + '}';
var data = 'data:text/css;charset=utf-8,' + encodeURI(css);
var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"]
.getService(Components.interfaces.nsIStyleSheetService);
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var u = ios.newURI(data, null, null);
if (sss.sheetRegistered(u, sss.USER_SHEET)) {
sss.unregisterSheet(u, sss.USER_SHEET);
}
sss.loadAndRegisterSheet(u, sss.USER_SHEET);
}
Maybe a simpler solution exists and my code is the worst way to proceed, if you know a better way please tell me
Amazon wish list
Adding a new stylesheet every time works, but here’s an idea for improvement.
CSS stylesheet rules actually have the “style” property, which works a lot like an element’s style property. If you had access to a stylesheet, any stylesheet, you could insert a rule with selector “.myTreeChildren::-moz-tree-cell-text” and keep a reference around to edit its properties.
Here’s how we do something similar in Fennec for resizing all sorts of elements automatically:
1. Grab the first stylesheet and add a rule http://mxr.mozilla.org/mobile-browser/source/chrome/content/browser.js#381
2. Edit the style property with your changes http://mxr.mozilla.org/mobile-browser/source/chrome/content/browser.js#405
Hope this helps
Comment by Benjamin Stover — January 8, 2010 @ 5:25 pm
Your code is very clear and simple, thank you very much
Comment by dafi — January 8, 2010 @ 5:31 pm
Did you succeeded to do it?
I tried to change style of tree dynamically. but it did not work.
I tried above code, but it does not seem to work for psudo-element of tree.
I also tried ‘insertRule’ method in the comment of ‘Benjamin Stover’.
I can see that my style inserted in the dom tree with DOM inspector.
However it does not applied to the tree.
Please help me.
Comment by tobwithu — April 14, 2010 @ 1:10 pm