What is a _Widget

The Impressive Quality Of Automated Trading

 

The auto-trading software is taking over the binary world, and robots such as Fintech Ltd are growing in popularity. Investors are turning towards this form of trading since it offers a broad range of benefits, but the primary advantage of this system is the fact that it delivers results, i.e. you can earn much more money than with manual trading.

by Peter Higgins

There has never been a more generic term than “widget”. As a teen in economics class our theoretical compaines sold widgets, and almost anything on earth without description falls into a “thinger” category … I’m here to give API stability to the word “widget”, and poke around the idea of “template” in Dojo. I will call it Dijit.

Torrey Rice recently explored Safari 3.1’s new CSS Animation support on the SitePen blog. While this kind of upcoming technology is wonderful, it doesn’t help to make my pages sexy now. I want simple FishEye effects today — using my existing technology — and it has to perform well everywhere. Even Internet Explorer.

Thankfully, I’d already done this, and Dojo made it really easy. I’m going to walk through my FisheyeLite DojoX component as an example use of dijit._Widget. You can look at the full source of the FisheyeLite as reference, but we’ll be generating most of the code along the way.

Start by setting up your module. There is no namespacing cookie just yet, but a slightly outdated _Widget tutorial in the Dojo Book explains the process pretty well.

This file lives in dojox/widget/FisheyeLite.js, so we’ll setup our provides and declaration to reflect that:

dojo.provide("dojox.widget.FisheyeLite");
// stuff needed:
dojo.require("dijit._Widget");
dojo.require("dojox.fx.easing");
// declare it:
dojo.declare("dojox.widget.FisheyeLite",
	dijit._Widget, // inherit from _Widget
	{
	postCreate: function(){
		// summary: my widget setup
		this.inherited(arguments);
	}
});

We can tie into any _Widget method by simply defining a function, and calling this.inherited(arguments) to execute the inherted method. By using postCreate we’re tying into a vital step in the Dijit lifecycle, and are injecting custom code.

At this point we can safely var fisheye = new dojox.widget.FisheyeLite({},node);, though nothing will happen. We need to setup some behavior, and add code to do what we need. We’ll assume all the rest of the code is contained within the dojo.declare object properties (the third argument).

The most convenient thing that comes from using _Widget as a base class: this.connect(). When called, it executes dojo.connect automatically hitched to the widget instance and stores the handle. When _Widget.destroy() is called, the connections are automatically cleaned up for us. In postCreate we’ll add a few connections to the node we used to create the widget, and add some methods to run when the events fire.

{
	postCreate: function(){
		this.inherited(arguments);
		this.connect(this.domNode,"onmouseover","show");
		this.connect(this.domNode,"onmouseout","hide");
		this.connect(this.domNode,"onclick","onClick");
	},
	show: function(e){
		// show the effect
	},
	hide: function(e){
		// remove the effect
	},
	onClick: function(e){
		// stub to override or hook into for user code
	}
}

A cavet of using this.connect is you are unable to manually disconnect the connection. If you need to start and stop your connections, you’d need to use dojo.connect directly:

     this._savedHandle = dojo.connect(this.domNode,"onclick",this,"onClick");
	 // and later:
	 dojo.disconnect(this._savedHandle);

The variable this.domNode is another benefit / side-effect of _Widget. It’s the top-level node used to create the widget instance. It’s just a pointer to the domNode, so we can use it as such (connect to it’s dom Events, appendChild, etc). This concept will be expanded on when we get into dijit._Templated. this.domNode is created if no node was passed the the creation, which is why after making a new _Widget (dijit) you have you place it somewhere if it wasn’t in the dom already:

// create a thinger, and append it to <body> tag
var foo = new my.Thinger({ prop:"erty" });
dojo.body().appendChild(foo.domNode);

At this point, we have a clean widget. A basic “getting started” custom Dijit example. If we want to allow a user to set options when they instantiate the Fisheye from markup we need to define those properites in our class. Dijit typically lists them out before the first piece of real code in a class:

dojo.declare("dojox.widget.FisheyeLite",
	dijit._Widget,{
 
	easeIn: "dojox.fx.easing.elasticOut",
	easeOut: "dojox.fx.easing.bounceOut",
	durationIn: 1200,
	durationOut: 500
 
	// ... snip, postCreate et al come next:
 
});

This allows us to set some default properties and variables to reuse, and allows the user to override those settings during instantiaion.

in markup:

<div id="foo" dojoType="dojox.widget.FisheyeLite" easeIn="dojox.fx.easing.bounceIn">Foo!</div>

from code:

var foo = new dojox.widget.FisheyeLite({
	durationOut: 1200,
	easeIn: "dojox.fx.easing.easeOut"
},"foo");

or from code the new fun 1.1 / dojo.query way:

	dojo.query("#foo")
		.instantiate(dojox.widget.FisheyeList,{
			easeIn: "dojox.fx.easing.bounceIn",
			durationOut: "1000"
		});

Inside our widget code, we can reference these settings anywhere. Calling _Widget.destroy() on our instance will cleanup any this.connect’s, and instance variables we created.

For the sake of simplicity in this article, I’ll spare you the walkthrough of the _makeAnims function in the FisheyeLite. Though if you look at the code, _makeAnims creates two animations based on the passed properties: parameter, and the behavioral .connect’s we created in postCreate call play() on whichever animation is needed. Its really simple, just beyond the “basics of _Widget”. The FisheyeLite is an excellent example of a very lightweight _Widget, with one heavy function only ever called once.

Now that we have the basics of _Widget worked out, we’ll move on into dojo.declare’s mixin. Above, we created a class based on _Widget, which provided us with some great convenience functionality. Changing the baseclass (above: _Widget) to an array of objects causes declare to use the first object as the baseclass and each subsequent object as a mixin. Each mixin is merged into the base class in order in the array. The most common occurance of this in Dijit looks a lot like:

dojo.provide("my.TemplatedThinger");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.declare("my.TemplatedThinger",
	[dijit._Widget, dijit._Templated],
	{
 
	templatePath: dojo.moduleUrl("my","templates/Thinger.html")
 
});

Neil already covered why templatePath: is cool, and what happens when you use it, so I’ll skip right on into “what mixing dijit._Templated actually does for us”. The crash course of Dijit Templating.

When the parser runs across the dom (using our my.Thinger class above):

<div dojoType="my.Thinger">Show foo.jpg</div>

it’s left in tact — Meaning the resulting dom is just a div with a .innerHTML of “Show foo.jpg” though our connections and whatnot have been applied.

When the parser runs across the dom:

<div dojoType="my.TemplatedThinger">Show foo.jpg</div>

we see something different happen. That div is replaced with the contents of templates/Thinger.html, and all sorts of other magic happens along the way. The magic is in the template markup. The most important rule about templates is we’re only allowed one top-level node. This node is what is placed in the dom in leui of the source node (the one with the dojoType, or the node we passed via new Thinger({},node);), so it only makes sense we’re only allowed one. We can, however, put as much content as we can imagine within that node and use some really powerful automation to make it even easier.

Let’s start with a simple node-replacement template:

<div class="myThinger">
	<div class="thingerHeader">Yep.</div>
	<div dojoAttachPoint="containerNode"></div>
</div>

Anytime we make a TemplatedThinger, a div with class=”myThinger” is created, and the resulting dom is replicated for all instances. Without any styling, all the above template will produce is “Yep” and “Show foo.jpg” on two lines. Our very most basic template introduces the first of _Templated magic, the “dojoAttachPoint”. Setting a dojoAttachPoint will create an instance variable pointing to the domNode the attribute was found on. We can access this.containerNode from anywhere within our widget code, and point to that node in the template.

“containerNode” is a very special node, much like “domNode”. In the above template, the node with class=”myThinger” is accessible as this.domNode by default. In _Templated, “containerNode” is use by the parser as a place to put content found in the original dom of a source node. “Show foo.jpg” (being the only content in the original dom) is placed in this.containerNode, resulting in “Yep”,”Show …” on two lines.

We can invent attachPoints, and name them what we like:

<div class="myThinger">
	<div dojoAttachPoint="wrapperNode">
		<div>
			<h1 dojoAttachPoint="headerNode">${title}</h1>
		</div>
		<div dojoAttachPoint="containerNode"></div>
	</div>
</div>

Now, this.wrapperNode is a reference to the overall wrapper around our containerNode and a new heading element accessible as this.headerNode. Same stuff, and really convenient when you get to actual coding. But wait! I see bling$.

_Templated does basic string replacements using a ${varname} syntax. Considering the two instances of my.TemplatedThinger:

	<div dojoType="my.TemplatedThinger" title="Hello Templates">Same thinger one</div>
	<div dojoType="my.TemplatedThinger" title="Okay I Get it, Move on">Another thinger</div>

each will have it’s title=”” attribute parsed, and injected into the template. ${title} is replaced by any content in the attribute. the key is: the attribute must exist in the one of the mixins or your own custom code either as a default, or a null value:

dojo.declare("a.Thinger",
	[dijit._Widget, dijit._Templated],{
 
	foo:"A default foo",
	bar:"",
	templateString:'<div><h1>${foo}</h1><div>${bar}</div>'
 
});

this.foo will default to “A default foo” for all instances, unless overridden. bar will be blank unless given a value. The lack of a dojoAttachPoint="containerNode" in the small template above will cause any content inside the original dom to be orphaned, and will cause weird things to happen. In a pinch, I just create a hidden containerNode:

<div>
	<div dojoAttachPoint="headerNode">${title}</div>
	<div dojoAttachPoint="containerNode" style="display:none"></div>
</div>

You get the added convenience of having access to the original content, and never have to show it to the client.

The last big secret about _Templated is dojoAttachEvent. This attribute, when specified in a template, will automatically connect and scope an event to itself. For example, a template named Foo.html:

<div>
	<h1 dojoAttachPoint="headerNode" dojoAttachEvent="onclick: _click">${title}</h1>
	<div dojoAttachPoint="containerNode"></div>
</div>

And some widget code:

dojo.declare("some.Thinger",
	// aka: "A templated widget"
	[dijit._Widget, dijit._Templated],
	{
 
	title:"",
	// after build, this is templateString:
	templatePath: dojo.module("some","templates/Foo.html"),
 
	_click: function(e){
		// the node this.headerNode got an onclick event
		if(this.headerNode == e.target){
			console.log("yep.");
		}
	}
});

Here, the dojoAttachEvent is the equilivant of calling:

this.connect(this.headerNode,"onclick","_click");

in some method of your Thinger class, though is done automatically for you, and eventually translates to less bytes on the wire by using the attachEvent method. As mentioned about this.connect, called thinger.destroy() will cleanup any listening events before removing the nodes created by the template.

That’s the basic’s on _Widget and _Templated, hope this helps. Here’s to making some really awesome widgets!

One important note about Dojo / declare / mixins / templates which is worth reading but not noting in this cookie: Understand objects and arrays and how they relate to Class prototypes.

Here’s a sample of a new “templated widget” I created, though it’s not fully ready for public consumption. Behold, the Image Skewer

Tags: Dijit, dojo.declare, DOM, templates, Widgets

About: Peter “dante” Higgins is the Dojo Toolkit Project Lead and a UI Designer at Joost.com
Website: http://higginsforpresident.net/

 

This entry was posted on Sunday, April 20th, 2008 at 1:27 pm and is filed under Dojo Cookies. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

11 Responses to “What is a _Widget”

  1. dante Says:
    Just as an updated note, “Wild” Bill Keese of Dijit fame pointed out to me you should be able to call _Widget.disconnect() on a handle returned by _Widget.connect(), making my statement about this.connect(node,event,method) not being able to be disconnected false. .connect() seems to return the handle just like dojo.connect() would, and disconnect() seems to successfully remove the connection from the this._connects hash. I stand corrected. Thanks bill –
  2. Great Dojo Widget tutorial « SOS Says:
    […] Posted by Shane O’Sullivan on 22 April, 2008 Pete Higgins has posted a great tutorial on how to write a Dojo widget, taking as an example his recent addition, FisheyeLite.  Check it out at http://dojocampus.org/content/?p=100 […]
  3. sabbaath Says:
    FYI,Dante’s example at the link above is broken. Some of the key code blocks are now empty. If you click through to his ImageAccordian html page example, several 404’s show up in firebug.sabbaath
  4. gtducati Says:
    Just out of curiosity, why is the widget class spelled as “_Widget?” I also noticed this for the calendar, namely “_Calendar.”
  5. dante Says:
    In dijit, the _ means a couple of things: If it’s inside of a Class, it means it’s a private member and not meant to be used directly (it could go away potentially, public methods, however, will not). In the case of _Widget, and _Calendar, it indicates, it simply means they are meant to be created directly, but rather to be used as a Base Class or Mixin for your own widgets. For instance, a dijit.form.DateTextBox uses a _Calendar as it’s popup.
  6. gtducati Says:
    That makes sense. So for dijit.form.DateTextBox, how exactly is the output of the _Calendar being serialized to this extended base class of dijit.form._DateTimeTextBox? Looking deeper, I can see that dijit.form._DateTimeTextBox is an extended class of dijit.form.RangeBoundTextBox, but dijit.form.RangeBoundTextBox isn’t anywhere in its expected directory; although, a dojo.require is calling dijit.form.ValidationTextBox. Can you see my confusion? :)
  7. dante Says:
    Yes. The Dijit.form stuff is particularly confusing in it’s inheritance chain. Not everything you dojo.require() only provide()’s that same thing. For instance, all the “buttons” (dropdown, and normal button) are in dijit.form.Button. TooltipDialog lives in dijit.Dialog.js –
  8. gtducati Says:
    Ok, so I’m looking in the right places. But back to my question in trying to understand how to make my own widget using _Calendar: how exactly is the output of the _Calendar being serialized to the textfield in dijit.form.DateTextBox?
  9. dante Says:
    The DataTextBox as a popupClass attribute, iirc. It is set to dijit._Calendar. The _Calendar is being created and managed directly by the TextBox widget, connecting to the Calendar’s onChange attribute to know when to show/hide/focus the input … You wouldn’t directly inherit from _Calendar at all, unless all you wanted was a _Calendar on a page, but typically, you’d want to wrap that in your own class as a shim to prevent the “private” _Calendar class from being access directly by your users (if you are making a product that other’s will build from)
  10. gtducati Says:
    Thanks for the insight. I’ll definitely be implementing something similar in the near future.
  11. Dojo and TinyMCE – Creating a Widget | GrasshopperPebbles.com Says:
    […] The Dojo widget that I created is based upon an implementation that I found on Disgruntleddevs.wordpress.com, but I changed the widget to make it more flexible – and I also don’t use a template (templatePath , templateString) with the widget because I did understand why it was needed. Also, while researching how to create a Dojo widget, I found a great article by Peter Higgins entitled, “What is a _Widget“. […]