Creating Dojo Templates
From ThemesWiki
| Official Page |
| Project Documentation |
| Download |
|
Contents |
[edit] Templates
Dojo actually supports two different templating langauges: the simple default and the Django Template Language (DTL, implemented originally in the Python Web framework of the same name).
Note that if you're using the first (standard) templating language, you're only allowed one element in the template! This is not as bad as it sounds. What it means is that you can only have one element with any number of children.
What will get you into trouble is if you have more than one element in your template parallel, or side-by-side, then only the first will get parsed.
The first supports simple variable substitutions, using ${..} syntax. For instance, you can define a HTML template snippet for a widget that includes a div tag which gets a custom id based upon the id given to the widget using the following:
<div id="${id}_custom"></div>
Health questoins answers online for womens health,health cooking health problems questions answered medical health blog health cooking recipes qa
That id would be the same property that is set as id="..." in the page where the widget is created and which also can be accessed using this.id inside the functions of the widget.
So all properties being set in the widget, by instantiation or dynamically (but before the template is rendered) can be used in this way inside the template string or file.
For a concrete example, look at the template for dijit.form.TextBox:
<input class="dijit dijitReset dijitLeft" dojoAttachPoint='textbox,
focusNode' name="${name}" dojoAttachEvent='onmouseenter:_onMouse,
onmouseleave:_onMouse,onfocus:_onMouse,
onblur:_onMouse,onkeypress:_onKeyPress' autocomplete="off" type="${type}" />
Inside the dijit/form/TextBox.js file, there are no definitions for these variables, however. But if we walk the class hierarchy we see that TextBox derives from a class called dijit.form._FormValueWidget. This class, in turn, inherits from dijit.form._FormWidget (and both superclasses are defined in the file with the same name.) Finally, we get to the variables:
//Name used when submitting form; same as "name" attribute or //plain HTML elements name: "", // alt: String //Corresponds to the native HTML <input> element's attribute. alt: "", // value: String //Corresponds to the native HTML <input> element's attribute. value: "", // type: String //Corresponds to the native HTML <input> element's attribute. type: "text",
So now you see that there is no magic underlying basic templating in Dojo. As long as you have a variable defined in a widget, even if it comes from a superclass or mixin (as you remember, a mixin is another (or more) multiple superclass, or a superclass added at runtime), it can be referred to in the template for the widget with the ${} syntax.
[edit] Attach points
Templates might contain fairly complex things, and it is not at all unusual to have the need to access DOM nodes inside the widget template after it has been instantiated. You might want to show or hide a dialog, or maybe add items dynamically to a list.
Either way, the quick and dirty way of doing this (as shown above) is to give the DOM node you want to access inside the widget template a dynamic id based upon the id of the widget, like this:
<div id="{id}_foo">
One could then use the following code in the actual JavaScript of the widget:
var x = dojo.byId(this.id+"_foo");
And x would always resolve to that particular node in the template, regardless of how many widgets of the same kind has been created in the page.
As it turns out, Dojo has excellent support for this, and it is called "Attach Points".
An Attach Point is a name you can give to any DOM node or Dijit in the template. Dojo will automatically scan the template for Attach Points and then create contextual this variables for the Dijit with the same names.
Consider a template that uses Attach Points instead, which looks like this:
<div><div dojoAttachPoint='foo'>XXXX</div><div dojoAttachPoint='bar'> YYYY</div></div>
What will happen when the Dijit is rendered in the page is that two new variables will be instantiated in the context of the Dijit, with the names 'foo' and 'bar', being references to the DOM nodes in question.
In the postCreate function of the widget, one could then have a line which reads:
this.foo.style.background = "#f94444";
This will change the background of the DOM node in the template, without having to know what DOM id it actually has, and without colliding with any other Dijits of the same (or other) type.
[edit] Events
But there were some other funny things in the template for TextBox, weren't there? There was a property called dojoAttachEvent, which is used expressly for the same reasons that one would use dojo.connect inside a script.
Let's look closer at those events:
dojoAttachEvent='onmouseenter:_onMouse...'
It is a series of comma-separated event names and function names pairs. In the case above, the event onmouseenter for the DOM node is connected to the function _onMouse in the TextBox widget class. This would otherwise be the prime reason for using Attach Points, so the code gets cleaner still.
[edit] Extension points
An extension point is what Dojo calls a function override inside the usual page. Several widgets aren't particularly useful unless you tell them what to do, such as the Button family. One way of telling a Button what to do is to create a small JavaScript somewhere in the page and use dojo.connect.
Another way could be to create you own widget which subclasses the Button widget, and then override the onClick function defined inside that widget using an extension point. We begin by checking out parts of the code in dijit.Button.js:
_onClick: function(/*Event*/ e)
{
// summary: internal function to handle click actions
if(this.disabled || this.readOnly)
{
dojo.stopEvent(e); // needed for checkbox
return false;
}
this._clicked(); // widget click actions
return this.onClick(e); // user click actions
},
This function is wired up to take care of click events for the widget. The last line of the widget calls another internal function, onClick, and returns the result of that. onClick looks like this:
onClick: function(/*Event*/ e)
{
//summary: user callback for when button is clicked
//if type="submit", return true to perform submit
return true;
},
To override this function by using an extension point, we can put the following in our page when declaring the Button widget:
<script>
function myfunc(e)
{
//Do something really clever with the event argument
}
</script>
<div dojoType="dijit.form.Button" onClick="myfunc"></div>
[edit] Django Templating Language (DTL)
DTL is a templating language for Dojo. Here you can define more complex widget markups using both loops and conditionals.
Where Dojo's classical templating system relied on variable substitutions, leaving the widget to create more complex dynamical markup in special functions and then put them in the template, DTL gives us much more power, or conversely allows our logic to become smaller.
To use DTL inside a widget, you must subclass dojox.dtl.Template and dojox.dtl.HtmlTemplate. The former manages all simple text substitutions, and the latter manages all other complex DOM manipulation.
So when defining a widget, instead of writing this:
dojo.declare("mycorp.charting.chart1", [ dijit._Widget, dijit._Templated],{...
You'd instead write the following:
dojo.declare("mycorp.charting.chart1", [ dijit._Widget, dojox.dtl._Templated],
{...
For example, we have a widget which reads data from the server using dojo.xhrGet and then puts all items read in a simple but sortable SortList.
Using a standard templating language, we might have built a template that looked something like this:
templateString="<ul dojoType="dojox.widget.SortList"></ul>";
And then have some widget code that looks like this:
// To be called when the server responds with data
handleData: function(data)
{
var obj = eval("("+data+")");
dojo.forEach(obj, function(o)
{
var li = document.createElement('li');
li.innerHTML = "" + o;
this.domNode.appendChild(li);
});
}
Instead, with DTL, we can change the template too look like this instead:
templateString="<ul dojoType="dojox.widget.SortList">{% for item in obj %}
<li>{{ item }}</li>{% endfor %}</ul>";
The code will be changed to only set the obj variable, which is used in the template, and the template itself then manages looping and variable substitution all on its own.
// changed to use DTL functionality instead. Obj is now an instance //variable.
handleData: function(data)
{
this.obj = eval("("+data+")");
}
To actually see the rendered data, DTL requires an extra step. You must at one point, when your variables are set up correctly, call the render function from dojox.dtl._Templated. But since your widget has mixed that class in, it is part of the 'this' context.
handleData: function(data)
{
this.obj = eval("("+data+")");
this.render();
}
However,dojox.widget.SortList is actually able to load its contents dynamically from a dojo.data store without any intervening widgets at all. I only use it as a daft but simple example on how one usually can go about creating dynamic content in a widget.
First, let's take a look at the features of DTL before we dive down into a longer example.
[edit] Variable substitution
Variables that we want to display from the widget are marked up differently.
{{person_name}}instead of${person_name}
[edit] Loops
The loops in DTL are reminiscent of server-based templating languages of yore, especially ASP and JSP.
Of course, these days the server need not do any templating or web magic at all, it only sends us data which gets rendered every which way in the Dojo client.
The variable item_list showing up in the example below are variables that exist in the 'this' context of the widget, and can be put there using widget parameter passing 'the usual way', just so you know.
<ul>
{% for item in item_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
[edit] Conditionals
{% if ordered_warranty %}
<p>Your warranty information will be included in the packaging.</p>
{% else %}
<p>No warranty for you!</p>
{% endif %}
[edit] Argument passing
As you remember from Chapter 2, a Dijit is just a Dojo class with some special properties. One of those properties is that if the Dijit class declares an explicit class variable, that variable will automatically be detected and initialized if present in the Dijit argument object
[edit] A recommended widget structure
The function dojo.require is a very powerful JavaScript loader. By creating a separate directory parallel to the Dojo directories, you will be able to load you own widgets (including having them auto-loading any of their dependencies) using just one dojo.require statement in your page.
There's another way to point out where to load classes from (this does of course not only relate to widgets, but we'll get to that in a minute).
This is how you might want to set things up for a new customer or project.
This is just an example, and you might want to set things up differently for a variety of reasons. We'll take each non-standard directory and file at a time and describe the reasons for where they're put.
| File/Directory | Meaning |
|---|---|
newcorp
| This is the name of your new project. The reason for putting this directory here is not only to make it simpler to use dojo.require for your project, but also to encapsulate all of your functionality in one folder.
|
templates
| Have at least one separate folder for your templates. As you'll see, you can use an inline string in the widget to avoid putting the widget template in a separate file. I advise against it, at least in the beginning. A separate file is great to pass around, and to change separately.
Sometimes you might choose to create separate subdirectories in the |
Styling
| Here I put the css files that are unique for each widget. Note that Dojo does not auto-load these css files, so you will still have to include them manually into your main html file.
Even so, I have come to rely upon having a separate directory for styling, to further modularize things from each other and to be able to focus on just the current widget. |
charting
| First things first here; charting is not a magic name in Dojo, it's just a sample name of the first widget created for the newcorp project. It could have been named foo instead.
But following the structure of the rest of Dojo, each area of functionality has its own subdirectory. If you were to create another component for newcorp that was a simple shopping cart, the next directory might be named |
test_chart1.html
| I usually put my test files in the root directory of the project. This is not completely normal, and Dojo usually provides a test subdirectory.
|
Chart1.html
| The HTML template for the mycorp.charting.chart1 widget
|
Chart1.css
| The CSS styles for the same |
Chart1.js
| The actual widget class which declares the widget and points out the template file. |
No matter how you choose to arrange the files, there are only two places which look up all the other things:
- The prime HTML file which actually loads the widget which you've created.
- The
.jsfile that defines the widget.
The parts which are critical here come usually in the beginning of the widget.
Let's look at a small example which fits into the scenario described above:
The chart1.js widget:
dojo.provide("mycorp.charting.chart1");
dojo.require("dijit._Templated");
dojo.require("dijit._Widget");
dojo.require("dojox.charting.Chart2D");
dojo.declare("mycorp.charting.chart1", [ dijit._Widget, dijit._Templated],
{
templatePath: dojo.moduleUrl("mycorp","templates/chart1.html"),
widgetsInTemplate: true,
startup: function()
{
console.log("startup for mycorp.charting.chart1 called.");
var ch = this.corpchart;
console.log("corpchart "+ch+" has id "+ch.id);
var chart1 = new dojox.charting.Chart2D(this.corpchart.id);
chart1.addSeries("Series A", [1, 2, 5, 4, 1, 3, 2,3,2,4,3,4],
{stroke: {color: "red", width: 2}});
chart1.addSeries("Series B", [7, 6, 3, 5, 4, 6, 5,6,7,5,2,5],
{stroke: {color: "blue", width: 2}});
chart1.render();
}
});
The first line of the widget declaration is dojo.provide. That call must contain a string that exactly references where in the namespace this widget (or class, actually) exists. Since this widget exists in the file mycorp/charting/chart1.js, the string will be mycorp.charting.chart1.
Then follows a number of required statements. The big upside with having required statements inside the widget definition is that it leaves the main HTML page relatively uncluttered. In fact, with some luck, all the script references you'll need is the one for dojo.js, and then a required statement for your widget. The rest of the Dojo classes will be pulled in dynamically as their required statements get discovered.
Let's have a look at the test page for our class:
<html>
<head><title>Chart1 Test</title></head>
<style type="text/css">
@import "../../../dojo/resources/dojo.css";
@import "styling/chart1.css";
</style>
<script>
var djConfig={ parseOnLoad: true};
</script>
<script type="text/javascript" src="../dojo/dojo.js"></script>
<script>
dojo.require("dojo.parser");
dojo.require("mycorp.charting.chart1");
</script>
<body>
<div dojoType="mycorp.charting.chart1"></div>
</body>
</html>
We include two CSS files: the Dojo reset styles and the specific styles for our widget. It can be a good idea to create versioned CSS files for each package (or project) that combine all styles into one file, for regular milestones. However, for everyday coding, it is generally better to have separate files.
After that we get the djConfig declaration which only tells the parser to begin parsing the page for Dijits immediately after load.
Then we pull in the main dojo loader dojo.js, and require first the parser, and then our widget.
The body of the test file is minimal, since all special markup for the widget is folded down into its template.
The CSS file is also very small and looks like this:
.mycorp_chart
{
height: 200px;
width: 400px;
}
And the template itself looks like this:
<div dojoAttachPoint="corpchart" class="mycorp_chart"></div>
Using the dojoAttachPoint property, a varaible gets created inside our widget, which we can refer to as this.corpchart and which is a reference to the DOM node in question.
If you try out the example and use firebug, you will see the following in the firebug console:
The id of the widget has been set to the namespace path of the widget, with _ replacing /, and a static counter tucked at the end.
The chart displayed will look approximately like this:
[edit] Themes
Themes are css files which make it possible to change the look and feel of Dijits with just a change in a base css class.
Dojo 0.9 came with the standard "tundra" theme with a Ext-like simplicity and elegance. Now in version 1.1 and counting we have the following themes (Images courtesy of dojotoolkit.org):
| Theme | Looks |
|---|---|
| Tundra | |
| Soria | |
| Noir (Under construction. Use at your own discretion.) |
There's also a fourth standard theme called "a11y", which is a theme for the visually impaired, with larger fonts, greater contrast, and so on.
Themes are set for Dojo widgets in the following way:
- Include the css file for the theme of your choices.
- Set the class of the body tag to the name of the theme.
The first point goes without saying, but the second might raise a couple of eyebrows. I have had clients that have flat out refused to touch the class of the body tag, concerned that the inclusion of the Dojo css files might break something further down in their design. This is a valid concern. It is a bit odd to use themes this way.
The reason for this is that a lot of complex widgets put all or parts of their elements directly under the body tag, so as not to interfere with the rest of the markup on the page.
Stuff are then placed or moved to the correct place on certain events, or just placed correctly from the beginning, but the element in question is still a child node of document.body.
This in turn means that if you don't put the theme class on the body tag, you'll end up with calendar widgets that look like dirt, and so on.
It would be unwise to recommend anyone to go against the expressed wishes of a client or project leader and just slap on the theme class anyway on the body tag using the following technique:
var theme = 'tundra';
if(!dojo.hasClass(dojo.body(),theme))
{
dojo.addClass(dojo.body(),theme);
}
But it has been known in parts of Sweden to totally rock and make life much easier.
[edit] I18N
Dojo uses Internationalization in all the official widgets under the dojo and dijit hierarchies. Only functionality in the experimental dojox hierarchy is exempt from I18N compliance.
Dojo uses specific JavaScript files for each function and language, so that it is comparatively simple to add translations and handling for locales which are not yet supported.
[edit] djConfig.locale
By setting the djConfig.locale variable, you can change the look and feel of Dojos widgets to better conform with other locales than en_us.
All Dijits that have some kind of semantic responsibility can and will show different behavior when a locale other than default is set.
Under the dijit folder in the Dojo directories, there's a folder called nls. In this folder, Dojo has put JavaScript files containing an object literal with resource strings for the classes with the same names.
As an example, there's a file called loading.js with the following content:
({
loadingState: "Loading...",
errorState: "Sorry, an error occurred"
})
We see that it contains two keys, loadingState and errorState, with default English values. Under the nls directory, there are quite a lot of subdirectories. They are named after the country codes they manage; cs, de, fr, pt, ru, and so on.
If we check in the de subdirectory, there's a loading-js file there as well, with the following content:
({
loadingState: "Wird geladen...",
errorState: "Es ist ein Fehler aufgetreten."
})
So, clearly, the nls system uses default resources in the base directory, with substitutable files with the same names and key-names, but with locale-corresponding content. Because these are JavaScript files, they can be managed and loaded lazily using the same techniques as the dojo.require loader does.
Every major Dijit or Dijit group has its own nls subdirectory. Under dijit.form, there's another nls directory, where we can see the same structure as that for the general dijit directory. A small number of default files ComboBox. js, TextArea.js and validate.js, are replicated in the subdirectory of each language.
If no djConfig.locale is configured, Dojo assumes that the locale to be used is the one configured for the browser. The function djConfig.extraLocale can be used to set one or more extra locales. Several locales can then be used for different widgets on the page.
[edit] Programmatic locale formatting
Using the following objects, you can leverage Dojos local-sensitivity to get dates, currency, and more in current locale format:
-
dojo.number.regexp -
dojo.number.parse -
dojo.date.locale.regexp -
dojo.date.locale.parse
For example, you can use the following to convert a date into different formats:
dojo.require("dojo.date.locale");
var d = new Date(2008,5,11,19,58);
var datestring = dojo.date.locale.format(d);
var ch_datestring = dojo.date.locale.format(d, {locale:'zh-cn'});
There's also a convenient system object called dojo.currency, which can be used to parse to and from different currency formats and locale specific formatting (which character to use for comma and such).
It is used in the following manner:
var dollarstring = dojo.currency.format(123.45, {currency: "USD", locale: "en-us"})
If you want to do the opposite, like parsing a numerical value from a correctly formatted currency string, you do this:
var value = dojo.currency.parse("$123.45", {currency: "USD", locale: "en-us"})
While we're on the subject, another really useful object is dojo.number.
Using this, you can format to and from a certain amount of digits, decimals, or templating strings, including locale specific support for commas.
dojo.number.format(123, {pattern: "0000"})
This gives the string "0123", for instance, whereas
dojo.number.format(-1234567.89, {pattern: "#,##,##0.000##"})
gives the string "-12,34,567.890".
[edit] Accessibility and graceful degradation
Dojo fully supports Accessible Rich Internet Applications (ARIA), which is a standard by the W3C Web Accessibility Initiative (WAI).
In practice, this means that all widgets are degradable and do not require a mouse to operate. An example of these can be found at Best Blu Ray Ripper and talked about here Dojo Templates Many elements inside the elements are tagged with "wai-roles", which can be used by the rendering browser to enable accessibility functionality for lower resolutions and more.Freestyle Medela
Firefox can use the roles defined in Dojo's widget templates to explain the page to a screen-reader for the visually impaired, and the roles can also be used for screen-scrapers and to allow for greater transparency towards indexing by search engines. Link Building Services Directory Submission logo design
[edit] Source
The source of this content is Chapter 3: Creating Dojo Templates of Learning Dojo by Peter Svensson (Packt Publishing, 2008).
Executive Editor Sean Lopez own : SEO Company and provider of Link Building Services and SEO Services
And Like Costumes and Halloween Costumes and criar sites
And Like The Global Information Network and Global Information Network
