General Interface is an open source project hosted by the Dojo Foundation

GI Contributor Blog Blog from Jan 18, 2011

  2011/01/18
Custom Matrix column using column formatter
Last Changed by Darren Hwang, Jan 18, 2011 17:28
Labels: matrix

Usage scenario

We have a requirement to display 3 different type of image buttons under a single column. Normally, you can only use one edit mask control under a column. So you cannot specify 3 different image button under a single column. This is one of the use case where custom column formatter comes in handy.

By using a custom column formatter we can generate 3 different type of image button depending on a record attribute (status).

Matrix Custom Format Handler
  instance.formatScheduleButton = function (objDiv, strCDFKey, objMatrix, objMatrixColumn, intRowNumber, objServer) {
    var status = objMatrix.getRecordNode(strCDFKey).getAttribute("status");

    var action = "Publish";
    if (status) {
      if (status == "started") {
        action = "Stop";
      } else if (status == "stopped") {
        action = "Start";
      }
    }
    var objPL = objMatrix.getAncestorOfType(pf.ProjectList);
    var buttonImage = KLASS.IMAGE_BUTTON_PATH + "Button_" + action + KLASS.IMAGE_EXT ;
    var sGetter = "jsx3.GO('" + objPL.getId() + "')";
    var handlers = " onmouseover=\"" + sGetter + ".onImageMouseover(event, this, '" + action + "')\" " +
                   " onmouseout=\"" + sGetter + ".onImageMouseout(event, this, '" + action + "')\" " +
                   " onmousedown=\"" + sGetter + ".onImageMousedown(event, this, '" + action + "')\" " +
                   " onclick=\"" + sGetter + ".onImageClick(event, this, '" + strCDFKey + "', '" + action + "')\" ";

    var strImageButton = "<span id='pfib_" + strCDFKey + "' " + " class='jsx30imagebutton' " + handlers + ">"
        + "<img width='80' height='22' src='" + objPL.getPlugIn().resolveURI(buttonImage) + "'/>" + "</span>";

    //jsx3.log(strImageButton);
    objDiv.innerHTML = strImageButton;

  };

The onmouseover, onmouseout and onmousedown DOM event handler are implemented to display the HOVER, Normal and DOWN images for each 3 types of buttons. onclick is the click event handler and there we decouple the view component from the model by using custom event publishing

Image button event handlers
  instance.onImageMouseover = function(evt, elm, action, imgExt) {
    var ext = (!imgExt) ? KLASS.IMAGE_EXT : imgExt;
    var imagePath = KLASS.IMAGE_BUTTON_PATH + "Button_" + action + "_rollover" + ext;
    elm.childNodes[0].src = this.getPlugIn().resolveURI(imagePath);
  };


  instance.onImageMouseout = function(evt, elm, action, imgExt) {
    var ext = (!imgExt) ? KLASS.IMAGE_EXT : imgExt;
    var imagePath = KLASS.IMAGE_BUTTON_PATH + "Button_" + action + ext;
    elm.childNodes[0].src = this.getPlugIn().resolveURI(imagePath);
  };


  instance.onImageMousedown = function(evt, elm, action, imgExt) {
    var ext = (!imgExt) ? KLASS.IMAGE_EXT : imgExt;
    var imagePath = KLASS.IMAGE_BUTTON_PATH + "Button_" + action + "_down" + ext;
    elm.childNodes[0].src = this.getPlugIn().resolveURI(imagePath);
  };


  instance.onImageClick = function(evt, elm, project, action) {
    LOG.debug("action=" + action + ", project=" + project);
    if (action == "Publish")
      this.getServer().publish({subject:"project.list.publish", name: project, status:action});
    else
      this.getServer().publish({subject:"project.list.schedule", name: project, status:action});
  };
Posted at 18 Jan @ 4:54 PM by Darren Hwang | 0 Comments
Using onBeforeDeserialize and onAfterDeserialize
Last Changed by Darren Hwang, Feb 02, 2011 23:24

Question came up on the forum regarding how to auto-populate a selection/combo control. The idea is to trigger a service request that will fetch the content for the select control.

To make use of onAfterDeserialize more "granular"

  1. ctrl+n to create a new canvas
  2. go back to the original canvas with your component
  3. open the Component Hiearchy palette and locate your component
  4. drag your component to the new canvas tab (the [ unsaved ] tab)
    The [ unsaved ] tab will show at this point
  5. drop your component into the new canvas
  6. save this new cavas containing only a single component as its own autoPopulateSelect.xml file
  7. enter your custom onBeforeDeserialize/onAfterDeserialize code, save and reload.

You've just created a single component serialization file with its own onBeforeDeserialize / onAfterDeserialize logic
To use this new custom component file

  1. Select the container block in original canvas in the Component Hiearchy palette and right click
  2. Choose Import Asynch to load the autoPopulateSelect.xml
About onAfterDeserialize and onBeforeDeserialize
Edit added before/after code. onAfterDeserialize is safer, but on onBeforeDeserialize is useful for things like manipulating the serialization file content before passing it to be rendered which is faster than modifying things on screen after the fact.
On Component Ready
Sometimes the component you are trying to access may not be ready to be manipulated inside onAfterDeserialize. Component such as Matrix control uses the GI asynch queue to provide better responsiveness in its operations. This can cause the component to be unavailable. In such case, you can place your code inside a jsx3.sleep() call to add it to the asynch queue and be called when it is ready.

Configuring the initial state of components is one of the use case for using onBeforeDesrialize. By modifying the serialization file content before the compoents are actually rendered. This helps optimize load performance by avoiding a double "paint" that can happen when using onAfterDeserialize, which re-render(repaint) the component after it's already rendered.

The following sample code will prompt you to choose an initial state of enabled=1 or disabled=0 for a Select/Combo control

<serialization jsxversion="3.9">
<name>
Layout - Top/Over
</name>
<icon>
images/prototypes/layout-over.gif
</icon>
<description>
2 top-over-bottom panes in an adaptive layout grid.
</description>
<onBeforeDeserialize>
var t = prompt(&quot;enable = 1, disable = 0&quot;); jsx3.log(t); var node = objXML.selectSingleNode(&quot;//jsx1:object[@type='jsx3.gui.Select']/jsx1:variants&quot; ); node.setAttribute(&quot;jsxenabled&quot;, &quot;&quot;+t);
</onBeforeDeserialize>
<onAfterDeserialize>
</onAfterDeserialize>
<object type="jsx3.gui.LayoutGrid">
<variants jsxrelativeposition="0" jsxleft="0" jsxtop="0" jsxoverflow="2"/>
<strings jsxname="layoutRows" jsxrows="100,*" jsxwidth="100%" jsxheight="100%"/>
<object type="jsx3.gui.Block">
<variants jsxoverflow="2"/>
<strings jsxname="pane1" jsxwidth="100%" jsxheight="100%"/>
<dynamics jsxborder="@Outset"/>
<object type="jsx3.gui.Select">
<variants jsxenabled="1" jsxwidth="150" jsxheight="18" jsxtype="1" jsxxmlasync="1"/>
<strings jsxname="combo" jsxxmlurl="jsx:///xml/sample.xml" jsxmargin="0 4 0 0" jsxdefaulttext="Select" jsxvalue="" jsxdisable=""/>
<events jsxchange="var x = this.getXML(); "/>
</object>
</object>
<object type="jsx3.gui.Block">
<variants jsxoverflow="1"/>
<strings jsxname="pane2" jsxwidth="100%" jsxheight="100%"/>
<dynamics jsxborder="@Outset"/>
</object>
</object>
</serialization>
Posted at 18 Jan @ 4:56 PM by Darren Hwang | 0 Comments