Snippets code from my daily experience

January 8, 2010

How to programmatically change XUL tree’s pseudo-classes

Filed under: extension,nsITreeView,xul — dafi @ 3:45 pm

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 :P.

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 :)

About these ads

3 Comments

  1. 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

  2. Your code is very clear and simple, thank you very much

    Comment by dafi — January 8, 2010 @ 5:31 pm

  3. 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


RSS feed for comments on this post.

The Rubric Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: