Usingnamespace – Blog

C#, XUL, Javascript, C++ …

Affichage des posts dans XUL

Unfortunately, there are no « clean » way to limit the maximum number of characters (or more generally apply constraints) in edit mode of a tree, unlike textbox elements.

Here is the trick : the oninput event of a tree is only fired when you are editing :

Short tree example (limiting max number of characters to 10):

<tree hidecolumnpicker="true" minwidth="100px" height="300" editable="true" flex="1" 
 oninput="event.originalTarget.value = event.originalTarget.value.substring(0,10);">
  <treecols>
    <treecol primary="true" flex="1"/>
  </treecols>
  <treechildren context="">
    <treeitem>
      <treerow>
        <treecell label="joe@somewhere.com"/>
      </treerow>
    </treeitem>
    <treeitem>
      <treerow>
        <treecell label="mel@whereever.com"/>
      </treerow>
    </treeitem>
  </treechildren>
</tree>

This is a very small tip, but if you don’t know it you might loose a lot of time on it !

To have a menupopup bigger than it’s parent menulist just set the attribute sizetopopup on the menulist to none:

sizetopopup
Type: one of the following values
Indicates how the menu width and the menupopup width are determined. If the sizetopopup attribute is left out or set to none, the menu will be its preferred width and the popup may extend outside of this width, unaffected by the maximum width of the menu itself.

* none: The width of the popup will not be constrained to the size of the menu.
* always: If set to always, the menu’s width will be the same as that necessary for the menupopup . If the menu has a maximum width, the popup will also be this width.

https://developer.mozilla.org/en/XUL/menulist#a-sizetopopup

I am pleased to share one creation of mine :) .

The following widget is a XBL binding based on the XUL’s XNL templates technology.
https://developer.mozilla.org/en/XUL/Template_Guide/XML_Templates

If you need to display xml data into a xul menulist -combobox- or in a radiogroup -radiobox-, without having to implement an XML parser, here is the solution :

xml-combobox
xml-radiobox

<xml-combobox id="myid" datasources="chrome://application/pathtoxmlfile" expr=""/>
<xml-radiobox id="myid" datasources="chrome://application/pathtoxmlfile" expr=""/>

Attributes :

datasources : URL of an XML document, either a local file or a remote web site.

expr : the expr attribute is a very simple XPath expression which simply retrieves the root elements of your query within the datasource.

label :

  • starting with « ! » : an XPath expression corresponding to the node you want to use as a label.
  • starting with « ? » : a property of the node corresponding to the expr result, you want to use as a label.
  • Otherwise just a text used as a label for all the generated lines (can be empty).



value :

  • starting with « ! » : an XPath expression corresponding to the node you want to use as a value.
  • starting with « ? » : a property of the node corresponding to the expr result, you want to use as a value.
  • Otherwise just a text used as a value for all the generated lines (can be empty).



image :

  • starting with « ! » : an XPath expression corresponding to the node you want to use as an image.
  • starting with « ? » : a property of the node corresponding to the expr result, you want to use as an image.
  • Otherwise just a text used as an image for all the generated lines (can be empty).



imageBaseFolder : if the attribute image is used, the base folder where to look the images for. Useful if the image query result is just a file name, or a relative path. Must contain the final « / » or « \ ». Can be left empty.

orient : (xml-radiobox only) : « horizontal » or « vertical ».

onselect: occurs when selection changed.

Examples :

Example 1 : simple example using the properties of a XML node

<people>
  <person name="Napoleon Bonaparte" id="NB"/>
  <person name="Cleopatra" id="Cl"/>
  <person name="Julius Caesar" id="JC"/>
  <person name="Ferdinand Magellan" id="FM"/>
  <person name="Laura Secord" id="LS"/>
</people>
<xml-combobox id="myid" datasources="chrome://application/pathtoxmlfile" expr="person/" label="?name" value="?id"/>

Example 2 : using a node property for the id and a XPath from the targeted node for the label (here the text contained in the subnode « name »)

<people>
  <person id="NB">
    <name>Napoleon Bonaparte</name>
    <gender>Male</gender>
  </person>
  <person id="Cl">
    <name>Cleopatra</name>
    <gender>Female</gender>
  </person>
  <person id="JC">
    <name>Julius Caesar</name>
    <gender>Male</gender>
  </person>
  <person id="FM">
    <name>Ferdinand Magellan</name>
    <gender>Male</gender>
  </person>
  <person id="LS">
    <name>Laura Secord</name>
    <gender>Female</gender>
  </person>
</people>
<xml-radiobox id="myid" datasources="chrome://application/pathtoxmlfile" expr="person/" label="!./name/text()" value="?id" orient="horizontal"/>

Example 3 : same as example 2 but with a xml-combobox and using the image property and imageBaseFolder to specify where the widget should look the images for

<people>
  <person id="NB">
    <name>Napoleon Bonaparte</name>
    <gender>Male</gender>
    <picture>nap.png</picture>
  </person>
  <person id="Cl">
    <name>Cleopatra</name>
    <gender>Female</gender>
    <picture>cleo.png</picture>
  </person>
  <person id="JC">
    <name>Julius Caesar</name>
    <gender>Male</gender>
    <picture>julius.png</picture>
  </person>
  <person id="FM">
    <name>Ferdinand Magellan</name>
    <gender>Male</gender>
    <picture>magellan.png</picture>
  </person>
  <person id="LS">
    <name>Laura Secord</name>
    <gender>Female</gender>
    <picture>secord.png</picture>
  </person>
</people>
<xml-combobox id="myid" datasources="chrome://application/pathtoxmlfile" expr="person/" label="!./name/text()" value="?id" imageBaseFolder="chrome://application/skin/pic_small/" image="!./picture/text()"/>

And like all the XBL widgets, the bindings need to be done in a CSS :

xml-combobox{
	-moz-binding: url("chrome://application/content/bindings/xml-combobox.xml#xml-combobox") !important;
}
 
xml-radiobox{
	-moz-binding: url("chrome://application/content/bindings/xml-radiobox.xml#xml-radiobox") !important;
}

Here are some useful functions I wrote or found on the web.
Suggestions are welcome :)

Chrome url to file path :

function chromeToPath (aChromePath) {
 
   if (!aChromePath) || !(/^chrome:/.test(aChromePath))))
      return; //not a chrome url
   var rv;
 
   var ios = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces["nsIIOService"]);
   var uri = ios.newURI(aPath, "UTF-8", null);
   var cr = Components.classes['@mozilla.org/chrome/chrome-registry;1'].getService(Components.interfaces["nsIChromeRegistry"]);
   rv = cr.convertChromeURL(uri).spec;
 
   if (/^file:/.test(rv))
      rv = this.urlToPath(rv);
   else
      rv = this.urlToPath("file://"+rv);
 
   return rv;
}

URL to file path :

function urlToPath (aURL) {
 
   if (!aURL || !/^file:/.test(aURL))
      return ;
   var rv;
   var ph = Components.classes["@mozilla.org/network/protocol;1?name=file"]
        .createInstance(Components.interfaces.nsIFileProtocolHandler);
    rv = ph.getFileFromURLSpec(aPath).path;
    return rv;
}

Get a nsILocalFile’s URL :

function pathToUrl (aFile) {
   //aFile must be an instance of nsILocalFile
   var rv;
   var ph = Components.classes["@mozilla.org/network/protocol;1?name=file"]
        .createInstance(Components.interfaces.nsIFileProtocolHandler);
    rv = ph.getURLSpecFromFile(aFile);
    return rv;
}

Check if file exists :

function fileExists(aPath){
  try {
    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
    var file = Components.classes["@mozilla.org/file/local;1"]
                         .createInstance(Components.interfaces.nsILocalFile);
    file.initWithPath(aPath);
    return file.exists();
  } catch(ex) {
    return false;
  }
}

Quit function :

function quit (aForceQuit) {
  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
  var appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1'].
    getService(Components.interfaces.nsIAppStartup);
 
  // eAttemptQuit will try to close each XUL window, but the XUL window can cancel the quit
  // process if there is unsaved data. eForceQuit will quit no matter what.
  var quitSeverity = aForceQuit ? Components.interfaces.nsIAppStartup.eForceQuit :
                                  Components.interfaces.nsIAppStartup.eAttemptQuit;
  appStartup.quit(quitSeverity);
}