2006/07/13

A simple color picker input on XUL

Today I'll show how to develop a binding that renders a simple color picker widget. This isn't something most people will need, but I did, so maybe you will too. This post also serves as a nice little example of the power and flexibility of XBL bindings.
I require a color picker input for an extension I'm currently working on. This extension requires that most interface elements to be customizable, styles included. This made having a color picker a mandatory requirement. So I started my quest for the information I'm about to give you. For free ;).
As usual, I thought at first that this was going to be real easy. I had some vague recollection of a XUL element that had this very purpose. So I looked it up and found it: the XUL colorpicker element. But alas, this was far from what I needed. This element is a little to low-level, if you look at it from the bright side. If you show the element as a button, you will see that this button opens as little popup that lets the user pick a color from a small grid. The problem is that clicking on any color on the grid does nothing. No color is picked. The grid remains open. It's just not fully functional. Or maybe I forgot to set the "pleasework" attribute to "true". Here's a screenshot of the element after being clicked:

But I'm not impatient, or too proud, so plan B sprung into action: looking for some extension that implements a color picker similar to the one I needed. After browsing around for a while, I found color pickers in the Colorzilla extension and the Nvu web authoring tool. Those two were a little too much for me. They required a new window and were way more advanced than what I needed. So that was a dead end too.
Well, not really. It kind of gave me the idea of what I needed to do to solve this problem: wrap the partly functional XUL element with a binding that gave me what I really needed. The question was, what did I need? I wanted something simple, so a functional colorpicker element might do. But then I thought that I also wanted something a little more flexible, that would allow more advanced users to pick any color they wanted. I had to find a compromise between complexity and functionality, and in the end I settled with this:

My idea was to have a colorpicker widget that included a textbox showing the picked color. Nothing particularly innovative, but it's not part of the current element set, as far as I know. This solution would allow novice users to pick basic colors from the grid, and the color they picked would be shown on the textbox. More advanced users would be able to type any valid CSS color they wanted in the textbox (including colors such as "black" or "rgb(234, 12, 0)"), and the button would show that color the user typed.
Since my color input required to behave as a single unit (I wanted a single "value" attribute that could be set from a template or read from a script), an XBL binding was in order. Here's the code for the binding and a little explanation about it:
<binding id="color-input">
<content>
<xul:hbox>
<xul:textbox anonid="color-textbox" inherits="value"
onchange="this.parentNode.parentNode.value = this.value; return true;" />
<xul:colorpicker anonid="color-picker" type="button" inherits="color=value"
onselect="this.parentNode.parentNode.value = this.mPicker.color; return true;" />
</xul:hbox>
</content>
<implementation>
<constructor><![CDATA[
var picker =
document.getAnonymousElementByAttribute(this, "anonid", "color-picker");
var color = this.getAttribute("value");
picker.initialize();
/* avoid problems with templates. */
if (color && (color.search("rdf:") < 0)) {
this.value = color;
} else {
this.value = "#000000";
}
]]></constructor>
<property name="value"
onget="return this.getAttribute('value');">
<setter><![CDATA[
var picker =
document.getAnonymousElementByAttribute(this, "anonid", "color-picker");
var textbox =
document.getAnonymousElementByAttribute(this, "anonid", "color-textbox");
picker.color = val;
textbox.value = val;
this.setAttribute("value", val);
]]></setter>
</property>
</implementation>
<handlers>
<handler event="DOMAttrModified"><![CDATA[
if(event.attrName == "value") {
this.value = event.newValue;
}
]]></handler>
</handlers>
</binding>
The color input would then be used in my XUL file as follows:
<colorinput value="black" />
Having the proper CSS binding set for the colorinput tag, obviously.
The content of the binding has two simple XUL elements: a textbox and a colorpicker. They both inherit the value attribute from the bound element, and they both implement methods that will update the "value" property when they are changed. The "onselect" handler in the colorpicker is worthy of notice, because that's one of the changes required to add proper functionality to the element. When a color is picked from the grid, this event is fired, but the "color" attribute is not changed, as it should. The "mPicker.color" property is the one that contains the newly selected color, so that's the one you want to use to set the value. The call of the "initialize" method on the picker is the other thing you need to keep in mind. For some reason the element is not properly initialized on the binding.
This binding is "template-friendly", as described on my Attributes and properties post. I also added a little validation on the constructor so that elements inside templates don't throw CSS errors. It's not a big deal, but the cleaner the better.
I've tested this input extensively and I'm very pleased with the end result. Hopefully this will prove to be useful for you as well.

Labels: , , , , , , ,


Comments:
Hi,
First of all...thank you for the great post on the color picker in firefox.
I am in the process of creating a tool where the user would be allowed to highlight any text selected on a web page in any color.This would be done by right clicking and selecting a color from the color picker.
I looked at your code...does this have to be implemented in javascript or simply added to the Xul file?

Thank you for your time and patience

Regards

Chris
 
Chris,
The main code fragment is XBL, which defines custom XUL tags. You can read about it here: https://developer.mozilla.org/En/XBL.
All that's required is an XML file with this code and a CSS file that binds the custom tag with this code. The rest is just including the tag wherever you need it.
It's pretty simple, it just takes a little effort getting the details right.
 
thanks alot for your promt reply! I managed!
Is it possible to display this color picker on the web page? (i.e DOM). Basically I wish to use the color picker when the user right clicks on the web page and the color picker would be like a sub menu.

Thanks once again
 
I was looking for code to use that on a Custom Button

Custom Buttons • View topic, Color Picker Any ever seen these used on a button?
Slider, Color Picker Any ever seen these used on a button?

Here is code for Darken Page button that has code to change the style of page (CSS sheet that colors the background, text colors and link colors)

Custom Buttons • View topic
Darken Page Button
 
I have a button with a dropdown menu with a slider and color picker on it. Can you know how to program it where the slider can lighten or darken page?
 
Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?