summaryrefslogtreecommitdiffstatshomepage
path: root/includes/js/dojox/dtl
diff options
context:
space:
mode:
Diffstat (limited to 'includes/js/dojox/dtl')
-rw-r--r--includes/js/dojox/dtl/Context.js87
-rw-r--r--includes/js/dojox/dtl/README207
-rw-r--r--includes/js/dojox/dtl/_HtmlTemplated.js72
-rw-r--r--includes/js/dojox/dtl/_Templated.js93
-rw-r--r--includes/js/dojox/dtl/_base.js570
-rw-r--r--includes/js/dojox/dtl/contrib/data.js89
-rw-r--r--includes/js/dojox/dtl/contrib/dijit.js220
-rw-r--r--includes/js/dojox/dtl/contrib/html.js107
-rw-r--r--includes/js/dojox/dtl/contrib/objects.js15
-rw-r--r--includes/js/dojox/dtl/demos/demo_Animation.html45
-rw-r--r--includes/js/dojox/dtl/demos/demo_Blog.html96
-rw-r--r--includes/js/dojox/dtl/demos/demo_Data.html58
-rw-r--r--includes/js/dojox/dtl/demos/demo_Dijitless.html50
-rw-r--r--includes/js/dojox/dtl/demos/demo_Events.html46
-rw-r--r--includes/js/dojox/dtl/demos/demo_HtmlTemplated.html40
-rw-r--r--includes/js/dojox/dtl/demos/demo_Inline.html48
-rw-r--r--includes/js/dojox/dtl/demos/demo_NodeList.html37
-rw-r--r--includes/js/dojox/dtl/demos/demo_Table.html4072
-rw-r--r--includes/js/dojox/dtl/demos/demo_Templated.html36
-rw-r--r--includes/js/dojox/dtl/demos/demo_Tree.html33
-rw-r--r--includes/js/dojox/dtl/demos/json/blog/get_blog_1.json1
-rw-r--r--includes/js/dojox/dtl/demos/json/blog/get_blog_3.json1
-rw-r--r--includes/js/dojox/dtl/demos/json/blog/get_blog_list.json1
-rw-r--r--includes/js/dojox/dtl/demos/json/blog/get_page_about.json1
-rw-r--r--includes/js/dojox/dtl/demos/json/fruit.json1
-rw-r--r--includes/js/dojox/dtl/demos/json/morefruit.json1
-rw-r--r--includes/js/dojox/dtl/demos/templates/animation.html5
-rw-r--r--includes/js/dojox/dtl/demos/templates/blog_base.html8
-rw-r--r--includes/js/dojox/dtl/demos/templates/blog_detail.html10
-rw-r--r--includes/js/dojox/dtl/demos/templates/blog_list.html9
-rw-r--r--includes/js/dojox/dtl/demos/templates/blog_page.html7
-rw-r--r--includes/js/dojox/dtl/demos/templates/countrychildren.html1
-rw-r--r--includes/js/dojox/dtl/demos/templates/gallery.html16
-rw-r--r--includes/js/dojox/dtl/demos/templates/nodelist.html5
-rw-r--r--includes/js/dojox/dtl/ext-dojo/NodeList.js33
-rw-r--r--includes/js/dojox/dtl/filter/dates.js54
-rw-r--r--includes/js/dojox/dtl/filter/htmlstrings.js59
-rw-r--r--includes/js/dojox/dtl/filter/integers.js32
-rw-r--r--includes/js/dojox/dtl/filter/lists.js137
-rw-r--r--includes/js/dojox/dtl/filter/logic.js34
-rw-r--r--includes/js/dojox/dtl/filter/misc.js59
-rw-r--r--includes/js/dojox/dtl/filter/strings.js327
-rw-r--r--includes/js/dojox/dtl/html.js818
-rw-r--r--includes/js/dojox/dtl/render/html.js76
-rw-r--r--includes/js/dojox/dtl/tag/date.js29
-rw-r--r--includes/js/dojox/dtl/tag/loader.js277
-rw-r--r--includes/js/dojox/dtl/tag/logic.js272
-rw-r--r--includes/js/dojox/dtl/tag/loop.js196
-rw-r--r--includes/js/dojox/dtl/tag/misc.js291
-rw-r--r--includes/js/dojox/dtl/tests/context.js79
-rw-r--r--includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html87
-rw-r--r--includes/js/dojox/dtl/tests/html/buffer.js35
-rw-r--r--includes/js/dojox/dtl/tests/html/tag.js233
-rw-r--r--includes/js/dojox/dtl/tests/html/util.js160
-rw-r--r--includes/js/dojox/dtl/tests/module.js15
-rw-r--r--includes/js/dojox/dtl/tests/runTests.html9
-rw-r--r--includes/js/dojox/dtl/tests/templates/hello.html1
-rw-r--r--includes/js/dojox/dtl/tests/templates/pocket.html1
-rw-r--r--includes/js/dojox/dtl/tests/templates/pocket2.html1
-rw-r--r--includes/js/dojox/dtl/tests/text/filter.js740
-rw-r--r--includes/js/dojox/dtl/tests/text/load.js6
-rw-r--r--includes/js/dojox/dtl/tests/text/tag.js480
-rw-r--r--includes/js/dojox/dtl/utils/date.js72
63 files changed, 10701 insertions, 0 deletions
diff --git a/includes/js/dojox/dtl/Context.js b/includes/js/dojox/dtl/Context.js
new file mode 100644
index 0000000..f608506
--- /dev/null
+++ b/includes/js/dojox/dtl/Context.js
@@ -0,0 +1,87 @@
+if(!dojo._hasResource["dojox.dtl.Context"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.Context"] = true;
+dojo.provide("dojox.dtl.Context");
+dojo.require("dojox.dtl._base");
+
+dojox.dtl.Context = dojo.extend(function(dict){
+ this._this = {};
+ dojox.dtl._Context.call(this, dict);
+}, dojox.dtl._Context.prototype,
+{
+ extend: function(/*dojox.dtl.Context|Object*/ obj){
+ // summary: Returns a clone of this context object, with the items from the
+ // passed objecct mixed in.
+ var context = new dojox.dtl.Context();
+ var keys = this.getKeys();
+ var i, key;
+ for(i = 0; key = keys[i]; i++){
+ if(typeof obj[key] != "undefined"){
+ context[key] = obj[key];
+ }else{
+ context[key] = this[key];
+ }
+ }
+
+ if(obj instanceof dojox.dtl.Context){
+ keys = obj.getKeys();
+ }else if(typeof obj == "object"){
+ keys = [];
+ for(key in obj){
+ keys.push(key);
+ }
+ }
+
+ for(i = 0; key = keys[i]; i++){
+ context[key] = obj[key];
+ }
+
+ return context;
+ },
+ filter: function(/*dojox.dtl.Context|Object|String...*/ filter){
+ // summary: Returns a clone of this context, only containing the items
+ // defined in the filter.
+ var context = new dojox.dtl.Context();
+ var keys = [];
+ var i, arg;
+ if(filter instanceof dojox.dtl.Context){
+ keys = filter.getKeys();
+ }else if(typeof filter == "object"){
+ for(var key in filter){
+ keys.push(key);
+ }
+ }else{
+ for(i = 0; arg = arguments[i]; i++){
+ if(typeof arg == "string"){
+ keys.push(arg);
+ }
+ }
+ }
+
+ for(i = 0, key; key = keys[i]; i++){
+ context[key] = this[key];
+ }
+
+ return context;
+ },
+ setThis: function(/*Object*/ _this){
+ this._this = _this;
+ },
+ getThis: function(){
+ return this._this;
+ },
+ hasKey: function(key){
+ if(typeof this[key] != "undefined"){
+ return true;
+ }
+
+ for(var i = 0, dict; dict = this._dicts[i]; i++){
+ if(typeof dict[key] != "undefined"){
+ return true;
+ }
+ }
+
+ return false;
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/README b/includes/js/dojox/dtl/README
new file mode 100644
index 0000000..a6cc8c3
--- /dev/null
+++ b/includes/js/dojox/dtl/README
@@ -0,0 +1,207 @@
+-------------------------------------------------------------------------------
+DojoX Django Template Language
+-------------------------------------------------------------------------------
+Version 0.0
+Release date: 09/20/2007
+-------------------------------------------------------------------------------
+Project state: experimental/feature incomplete
+-------------------------------------------------------------------------------
+Project authors
+ Neil Roberts (pottedmeat@dojotoolkit.org)
+-------------------------------------------------------------------------------
+Project description
+
+The Django Template language uses a system of templates that can be compiled
+once and rendered indefinitely afterwards. It uses a simple system of tags
+and filters.
+
+This is a 1:1 match with the Django Template Language as outlined in
+http://www.djangoproject.com/documentation/templates/. All applicable tags and
+filters have been implemented (see below), along with new filters and tags as
+necessary (see below).
+
+The Django Template Language is intended within Django to only handle text.
+Our implementation is able to handle HTML in addition to text. Actually, the
+text and HTML portions of dojox.dtl are two separate layers, the HTML layer
+sits on top of the text layer (base). It's also been implemented in such a way
+that you have little to fear when moving your code from Django to dojox.dtl.
+Your existing templates should work, and will benefit from the massive
+performance gain of being able to manipulate nodes, rather than having to do
+clunky innerHTML swaps you would have to do with a text-only system. It also
+allows for new HTML-centric abilities, outlined below.
+
+Despite having two levels of complexity, if you write your tags correctly, they
+will work in both environments.
+-------------------------------------------------------------------------------
+Dependencies
+
+Base:
+dojox.string.Builder
+
+Date filters and tags:
+dojox.date.php
+
+Widget:
+dijit._Widget
+dijit._Container
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/dtl.js
+http://svn.dojotoolkit.org/var/src/dojo/dojox/trunk/dtl/*
+
+Install into the following directory structure:
+/dojox/dtl/
+
+...which should be at the same level as your Dojo checkout.
+-------------------------------------------------------------------------------
+What's Been Done
+
+Note: HTML Unit Tests should only be around for the oddities of HTML, tag/filter
+code is the same for each environment with minor exceptions. Cloning of all tags
+should be tested inside a for loop.
+
+| Implemented | Tag | Text Unit Test | HTML Unit Test |
+| X | block | X | |
+| X | comment | X | |
+| X | cycle | X | |
+| X | debug | X | |
+| X | extends | X | |
+| X | filter | X | |
+| X | firstof | X | |
+| X | for | X | |
+| X | if | X | |
+| X | ifchanged | X | X |
+| X | ifequal | X | |
+| X | ifnotequal | X | |
+| X | include | X | X |
+| X | load | X | |
+| X | now | X | |
+| X | regroup | X | |
+| X | spaceless | X | X |
+| X | ssi | X | X |
+| X | templatetag | X | |
+| N/A | url | | |
+| X | widthratio | X | |
+| X | with | X | |
+
+| Implemented | Filter | Text Unit Test | HTML Unit Test |
+| X | add | X | |
+| X | addslashes | X | |
+| X | capfirst | X | |
+| X | center | X | |
+| X | cut | X | |
+| X | date | X | |
+| X | default | X | |
+| X | default_if_none | X | |
+| X | dictsort | X | |
+| X | dictsort_reversed | X | |
+| X | divisibleby | X | |
+| X | escape | X | |
+| X | filesizeformat | X | |
+| X | first | X | |
+| X | fix_ampersands | X | |
+| X | floatformat | X | |
+| X | get_digit | X | |
+| X | iriencode | X | |
+| X | join | X | |
+| X | length | X | |
+| X | length_is | X | |
+| X | linebreaks | X | |
+| X | linebreaksbr | X | |
+| X | linenumbers | X | |
+| X | ljust | X | |
+| X | lower | X | |
+| X | make_list | X | |
+| X | phone2numeric | X | |
+| X | pluralize | X | |
+| X | pprint | X | |
+| X | random | X | |
+| X | removetags | X | |
+| X | rjust | X | |
+| X | slice | X | |
+| X | slugify | X | |
+| X | stringformat | X | |
+| X | striptags | X | |
+| X | time | X | |
+| X | timesince | X | |
+| X | timeuntil | X | |
+| X | title | X | |
+| X | truncatewords | X | |
+| X | truncatewords_html | X | |
+| X | unordered_list | X | |
+| X | upper | X | |
+| X | urlencode | X | |
+| X | urlize | X | |
+| X | urlizetrunc | X | |
+| X | wordcount | X | |
+| X | wordwrap | X | |
+| X | yesno | X | |
+-------------------------------------------------------------------------------
+HTML-Specific Additions
+-------------------------------------------------------------------------------
+{%extends "shared:templates/template.html" %}
+
+When using the {% extends %} tag, we don't always want to replace the parent
+node in DOM. For example, if we have a list view and a detail view, but both
+share the same base template, we want it to share the parent template. This
+basically means that the same nodes will be used in the parent for both views.
+
+To use this, simply add "shared:" to the beginning of the specified template.
+-------------------------------------------------------------------------------
+<!--{% commented markup %}-->
+
+Some browsers treat comment nodes as full fledged nodes. If performance is
+important to you, you can wrap your markup in comments. The comments will be
+automatically stripped for browsers that cannot support this.
+-------------------------------------------------------------------------------
+Attribute Tags
+
+If a tag name begins with "attr:" then it will be able to inject an object
+into the parsed template. (See dojox.dtl.tag.event.EventNode)
+
+onclick/onmouseover/etc attributes work by attaching to the rendering object.
+
+tstyle attribute allows for styles to be changed dynamically. Use them just
+like a "style" attribute.
+
+attach attribute attaches the node to the rendering object.
+-------------------------------------------------------------------------------
+New Context Functions
+
+setThis() and getThis() returns the object "in charge" of the current rendering.
+This is used so that we can attach events.
+
+mixin() and filter() clone the current context, and either add to or reduce
+the keys in the context.
+-------------------------------------------------------------------------------
+Buffers
+
+Both the base and HTML versions of dojox.dtl use buffers. The base version uses
+dojox.string.Builder and the HTML version uses dojox.dtl.HtmlBuffer.
+
+The HTML buffer has several calls important to rendering:
+
+setParent/getParent/concat/remove:
+
+setParent and concat are used in order to render our HTML. As we move through
+the parsed template, different nodes change the parent or add on to the
+current parent. getParent is useful in things like the attribute tags, since
+they can use getParent to find the node that they're an attribute on. remove is
+used during unrendering.
+
+setAttribute:
+
+Sets an attribute on the current parent
+-------------------------------------------------------------------------------
+Tags Need clone/unrender Functions.
+
+One of the biggest challenges of getting dojox.dtl to work in an HTML
+environment was logic blocks. Nodes and objects inside a for loop need to be
+cloned, they can't simply be re-rendered, especially if they involve a Node.
+Also, in the case of an if/else block, we need to be able to not just render
+one of the blocks, but also unrender the second.
+
+This is really simple code, a good example is the dojox.dtl.HtmlNode
+object. Each function in this object is only one line long. \ No newline at end of file
diff --git a/includes/js/dojox/dtl/_HtmlTemplated.js b/includes/js/dojox/dtl/_HtmlTemplated.js
new file mode 100644
index 0000000..8947a8d
--- /dev/null
+++ b/includes/js/dojox/dtl/_HtmlTemplated.js
@@ -0,0 +1,72 @@
+if(!dojo._hasResource["dojox.dtl._HtmlTemplated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl._HtmlTemplated"] = true;
+dojo.provide("dojox.dtl._HtmlTemplated");
+dojo.require("dijit._Templated");
+dojo.require("dojox.dtl.html");
+dojo.require("dojox.dtl.render.html");
+dojo.require("dojox.dtl.contrib.dijit");
+
+dojox.dtl._HtmlTemplated = {
+ prototype: {
+ _dijitTemplateCompat: false,
+ buildRendering: function(){
+ this.domNode = this.srcNodeRef;
+
+ if(!this._render){
+ var ddcd = dojox.dtl.contrib.dijit;
+ var old = ddcd.widgetsInTemplate;
+ ddcd.widgetsInTemplate = this.widgetsInTemplate;
+ this._template = this._getCachedTemplate(this.templatePath, this.templateString);
+ this._render = new dojox.dtl.render.html.Render(this.domNode, this._template);
+ ddcd.widgetsInTemplate = old;
+ }
+
+ var self = this;
+ this._rendering = setTimeout(function(){ self.render(); }, 10);
+ },
+ setTemplate: function(/*String|dojo._Url*/ template, /*dojox.dtl.Context?*/ context){
+ // summary:
+ // Quickly switch between templated by location
+ if(dojox.dtl.text._isTemplate(template)){
+ this._template = this._getCachedTemplate(null, template);
+ }else{
+ this._template = this._getCachedTemplate(template);
+ }
+ this.render(context);
+ },
+ render: function(/*dojox.dtl.Context?*/ context){
+ if(this._rendering){
+ clearTimeout(this._rendering);
+ delete this._rendering;
+ }
+ this._render.render(this._getContext(context));
+ },
+ _getContext: function(context){
+ if (!(context instanceof dojox.dtl.Context)) {
+ context = false;
+ }
+ context = context || new dojox.dtl.Context(this);
+ context.setThis(this);
+ return context;
+ },
+ _getCachedTemplate: function(templatePath, templateString){
+ if(!this._templates){
+ this._templates = {};
+ }
+ var key = templateString || templatePath.toString();
+ var tmplts = this._templates;
+ if(tmplts[key]){
+ return tmplts[key];
+ }
+ return (tmplts[key] = new dojox.dtl.HtmlTemplate(
+ dijit._Templated.getCachedTemplate(
+ templatePath,
+ templateString,
+ true
+ )
+ ));
+ }
+ }
+};
+
+}
diff --git a/includes/js/dojox/dtl/_Templated.js b/includes/js/dojox/dtl/_Templated.js
new file mode 100644
index 0000000..1472fe9
--- /dev/null
+++ b/includes/js/dojox/dtl/_Templated.js
@@ -0,0 +1,93 @@
+if(!dojo._hasResource["dojox.dtl._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl._Templated"] = true;
+dojo.provide("dojox.dtl._Templated");
+dojo.require("dijit._Templated");
+dojo.require("dojox.dtl._base");
+
+dojo.declare("dojox.dtl._Templated", dijit._Templated, {
+ _dijitTemplateCompat: false,
+ buildRendering: function(){
+ var node;
+
+ if(this.domNode && !this._template){
+ return;
+ }
+
+ if(!this._template){
+ var t = this.getCachedTemplate(
+ this.templatePath,
+ this.templateString,
+ this._skipNodeCache
+ );
+ if(t instanceof dojox.dtl.Template) {
+ this._template = t;
+ }else{
+ node = t;
+ }
+ }
+ if(!node){
+ var nodes = dijit._Templated._createNodesFromText(
+ this._template.render(new dojox.dtl._Context(this))
+ );
+ for(var i = 0; i < nodes.length; i++){
+ if(nodes[i].nodeType == 1){
+ node = nodes[i];
+ break;
+ }
+ }
+ }
+
+ this._attachTemplateNodes(node);
+
+ var source = this.srcNodeRef;
+ if(source && source.parentNode){
+ source.parentNode.replaceChild(node, source);
+ }
+
+ if(this.widgetsInTemplate){
+ var childWidgets = dojo.parser.parse(node);
+ this._attachTemplateNodes(childWidgets, function(n,p){
+ return n[p];
+ });
+ }
+
+ if(this.domNode){
+ dojo.place(node, this.domNode, "before");
+ this.destroyDescendants();
+ dojo._destroyElement(this.domNode);
+ }
+ this.domNode = node;
+
+ this._fillContent(source);
+ },
+ _templateCache: {},
+ getCachedTemplate: function(templatePath, templateString, alwaysUseString){
+ // summary:
+ // Layer for dijit._Templated.getCachedTemplate
+ var tmplts = this._templateCache;
+ var key = templateString || templatePath;
+ if(tmplts[key]){
+ return tmplts[key];
+ }
+
+ templateString = dojo.string.trim(templateString || dijit._Templated._sanitizeTemplateString(dojo._getText(templatePath)));
+
+ if( this._dijitTemplateCompat &&
+ (alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g))
+ ){
+ templateString = this._stringRepl(templateString);
+ }
+
+ // If we always use a string, or find no variables, just store it as a node
+ if(alwaysUseString || !templateString.match(/\{[{%]([^\}]+)[%}]\}/g)){
+ return (tmplts[key] = dijit._Templated._createNodesFromText(templateString)[0]);
+ }else{
+ return (tmplts[key] = new dojox.dtl.Template(templateString));
+ }
+ },
+ render: function(){
+ this.buildRendering();
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/_base.js b/includes/js/dojox/dtl/_base.js
new file mode 100644
index 0000000..f42f245
--- /dev/null
+++ b/includes/js/dojox/dtl/_base.js
@@ -0,0 +1,570 @@
+if(!dojo._hasResource["dojox.dtl._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl._base"] = true;
+dojo.provide("dojox.dtl._base");
+
+dojo.require("dojox.string.Builder");
+dojo.require("dojox.string.tokenize");
+
+(function(){
+ var dd = dojox.dtl;
+
+ dd._Context = dojo.extend(function(dict){
+ // summary: Pass one of these when rendering a template to tell the template what values to use.
+ dojo.mixin(this, dict || {});
+ this._dicts = [];
+ },
+ {
+ push: function(){
+ var dict = {};
+ var keys = this.getKeys();
+ for(var i = 0, key; key = keys[i]; i++){
+ dict[key] = this[key];
+ delete this[key];
+ }
+ this._dicts.unshift(dict);
+ },
+ pop: function(){
+ if(!this._dicts.length){
+ throw new Error("pop() called on empty Context");
+ }
+ var dict = this._dicts.shift();
+ dojo.mixin(this, dict);
+ },
+ getKeys: function(){
+ var keys = [];
+ for(var key in this){
+ if(this.hasOwnProperty(key) && key != "_dicts" && key != "_this"){
+ keys.push(key);
+ }
+ }
+ return keys;
+ },
+ get: function(key, otherwise){
+ if(typeof this[key] != "undefined"){
+ return this._normalize(this[key]);
+ }
+
+ for(var i = 0, dict; dict = this._dicts[i]; i++){
+ if(typeof dict[key] != "undefined"){
+ return this._normalize(dict[key]);
+ }
+ }
+
+ return otherwise;
+ },
+ _normalize: function(value){
+ if(value instanceof Date){
+ value.year = value.getFullYear();
+ value.month = value.getMonth() + 1;
+ value.day = value.getDate();
+ value.date = value.year + "-" + ("0" + value.month).slice(-2) + "-" + ("0" + value.day).slice(-2);
+ value.hour = value.getHours();
+ value.minute = value.getMinutes();
+ value.second = value.getSeconds();
+ value.microsecond = value.getMilliseconds();
+ }
+ return value;
+ },
+ update: function(dict){
+ this.push();
+ if(dict){
+ dojo.mixin(this, dict);
+ }
+ }
+ });
+
+ var ddt = dd.text = {
+ types: {tag: -1, varr: -2, text: 3},
+ pySplit: function(str){
+ // summary: Split a string according to Python's split function
+ str = dojo.trim(str);
+ return (!str.length) ? [] : str.split(/\s+/g);
+ },
+ _get: function(module, name, errorless){
+ // summary: Used to find both tags and filters
+ var params = dd.register.get(module, name.toLowerCase(), errorless);
+ if(!params){
+ if(!errorless){
+ throw new Error("No tag found for " + name);
+ }
+ return null;
+ }
+
+ var fn = params[1];
+ var require = params[2];
+
+ var parts;
+ if(fn.indexOf(":") != -1){
+ parts = fn.split(":");
+ fn = parts.pop();
+ }
+
+ dojo["require"](require);
+
+ var parent = dojo.getObject(require);
+
+ return parent[fn || name] || parent[name + "_"];
+ },
+ getTag: function(name, errorless){
+ return ddt._get("tag", name, errorless);
+ },
+ getFilter: function(name, errorless){
+ return ddt._get("filter", name, errorless);
+ },
+ getTemplate: function(file){
+ return new dd.Template(dd.getTemplateString(file));
+ },
+ getTemplateString: function(file){
+ return dojo._getText(file.toString()) || "";
+ },
+ _resolveLazy: function(location, sync, json){
+ if(sync){
+ if(json){
+ return dojo.fromJson(dojo._getText(location)) || {};
+ }else{
+ return dd.text.getTemplateString(location);
+ }
+ }else{
+ return dojo.xhrGet({
+ handleAs: (json) ? "json" : "text",
+ url: location
+ });
+ }
+ },
+ _resolveTemplateArg: function(arg, sync){
+ if(ddt._isTemplate(arg)){
+ if(!sync){
+ var d = new dojo.Deferred();
+ d.callback(arg);
+ return d;
+ }
+ return arg;
+ }
+ return ddt._resolveLazy(arg, sync);
+ },
+ _isTemplate: function(arg){
+ return (typeof arg == "undefined") || (dojo.isString(arg) && (arg.match(/^\s*[<{]/) || arg.indexOf(" ") != -1));
+ },
+ _resolveContextArg: function(arg, sync){
+ if(arg.constructor == Object){
+ if(!sync){
+ var d = new dojo.Deferred;
+ d.callback(arg);
+ return d;
+ }
+ return arg;
+ }
+ return ddt._resolveLazy(arg, sync, true);
+ },
+ _re: /(?:\{\{\s*(.+?)\s*\}\}|\{%\s*(load\s*)?(.+?)\s*%\})/g,
+ tokenize: function(str){
+ return dojox.string.tokenize(str, ddt._re, ddt._parseDelims);
+ },
+ _parseDelims: function(varr, load, tag){
+ var types = ddt.types;
+ if(varr){
+ return [types.varr, varr];
+ }else if(load){
+ var parts = dd.text.pySplit(tag);
+ for(var i = 0, part; part = parts[i]; i++){
+ dojo["require"](part);
+ }
+ }else{
+ return [types.tag, tag];
+ }
+ }
+ }
+
+ dd.Template = dojo.extend(function(/*String|dojo._Url*/ template){
+ // template:
+ // The string or location of the string to
+ // use as a template
+ var str = ddt._resolveTemplateArg(template, true) || "";
+ var tokens = ddt.tokenize(str);
+ var parser = new dd._Parser(tokens);
+ this.nodelist = parser.parse();
+ },
+ {
+ update: function(node, context){
+ // node: DOMNode|String|dojo.NodeList
+ // A node reference or set of nodes
+ // context: dojo._Url|String|Object
+ // The context object or location
+ return ddt._resolveContextArg(context).addCallback(this, function(contextObject){
+ var content = this.render(new dd._Context(contextObject));
+ if(node.forEach){
+ node.forEach(function(item){
+ item.innerHTML = content;
+ });
+ }else{
+ dojo.byId(node).innerHTML = content;
+ }
+ return this;
+ });
+ },
+ render: function(context, /*concatenatable?*/ buffer){
+ buffer = buffer || this.getBuffer();
+ context = context || new dd._Context({});
+ return this.nodelist.render(context, buffer) + "";
+ },
+ getBuffer: function(){
+ dojo.require("dojox.string.Builder");
+ return new dojox.string.Builder();
+ }
+ });
+
+ dd._Filter = dojo.extend(function(token){
+ // summary: Uses a string to find (and manipulate) a variable
+ if(!token) throw new Error("Filter must be called with variable name");
+ this.contents = token;
+
+ var cache = this._cache[token];
+ if(cache){
+ this.key = cache[0];
+ this.filters = cache[1];
+ }else{
+ this.filters = [];
+ dojox.string.tokenize(token, this._re, this._tokenize, this);
+ this._cache[token] = [this.key, this.filters];
+ }
+ },
+ {
+ _cache: {},
+ _re: /(?:^_\("([^\\"]*(?:\\.[^\\"])*)"\)|^"([^\\"]*(?:\\.[^\\"]*)*)"|^([a-zA-Z0-9_.]+)|\|(\w+)(?::(?:_\("([^\\"]*(?:\\.[^\\"])*)"\)|"([^\\"]*(?:\\.[^\\"]*)*)"|([a-zA-Z0-9_.]+)|'([^\\']*(?:\\.[^\\']*)*)'))?|^'([^\\']*(?:\\.[^\\']*)*)')/g,
+ _values: {
+ 0: '"', // _("text")
+ 1: '"', // "text"
+ 2: "", // variable
+ 8: '"' // 'text'
+ },
+ _args: {
+ 4: '"', // :_("text")
+ 5: '"', // :"text"
+ 6: "", // :variable
+ 7: "'"// :'text'
+ },
+ _tokenize: function(){
+ var pos, arg;
+
+ for(var i = 0, has = []; i < arguments.length; i++){
+ has[i] = (typeof arguments[i] != "undefined" && dojo.isString(arguments[i]) && arguments[i]);
+ }
+
+ if(!this.key){
+ for(pos in this._values){
+ if(has[pos]){
+ this.key = this._values[pos] + arguments[pos] + this._values[pos];
+ break;
+ }
+ }
+ }else{
+ for(pos in this._args){
+ if(has[pos]){
+ var value = arguments[pos];
+ if(this._args[pos] == "'"){
+ value = value.replace(/\\'/g, "'");
+ }else if(this._args[pos] == '"'){
+ value = value.replace(/\\"/g, '"');
+ }
+ arg = [!this._args[pos], value];
+ break;
+ }
+ }
+ // Get a named filter
+ var fn = ddt.getFilter(arguments[3]);
+ if(!dojo.isFunction(fn)) throw new Error(arguments[3] + " is not registered as a filter");
+ this.filters.push([fn, arg]);
+ }
+ },
+ getExpression: function(){
+ return this.contents;
+ },
+ resolve: function(context){
+ var str = this.resolvePath(this.key, context);
+ for(var i = 0, filter; filter = this.filters[i]; i++){
+ // Each filter has the function in [0], a boolean in [1][0] of whether it's a variable or a string
+ // and [1][1] is either the variable name of the string content.
+ if(filter[1]){
+ if(filter[1][0]){
+ str = filter[0](str, this.resolvePath(filter[1][1], context));
+ }else{
+ str = filter[0](str, filter[1][1]);
+ }
+ }else{
+ str = filter[0](str);
+ }
+ }
+ return str;
+ },
+ resolvePath: function(path, context){
+ var current, parts;
+ var first = path.charAt(0);
+ var last = path.slice(-1);
+ if(!isNaN(parseInt(first))){
+ current = (path.indexOf(".") == -1) ? parseInt(path) : parseFloat(path);
+ }else if(first == '"' && first == last){
+ current = path.slice(1, -1);
+ }else{
+ if(path == "true"){ return true; }
+ if(path == "false"){ return false; }
+ if(path == "null" || path == "None"){ return null; }
+ parts = path.split(".");
+ current = context.get(parts[0]);
+ for(var i = 1; i < parts.length; i++){
+ var part = parts[i];
+ if(current){
+ if(dojo.isObject(current) && part == "items" && typeof current[part] == "undefined"){
+ var items = [];
+ for(var key in current){
+ items.push([key, current[key]]);
+ }
+ current = items;
+ continue;
+ }
+
+ if(current.get && dojo.isFunction(current.get)){
+ current = current.get(part);
+ }else if(typeof current[part] == "undefined"){
+ current = current[part];
+ break;
+ }else{
+ current = current[part];
+ }
+
+ if(dojo.isFunction(current)){
+ if(current.alters_data){
+ current = "";
+ }else{
+ current = current();
+ }
+ }
+ }else{
+ return "";
+ }
+ }
+ }
+ return current;
+ }
+ });
+
+ dd._TextNode = dd._Node = dojo.extend(function(/*Object*/ obj){
+ // summary: Basic catch-all node
+ this.contents = obj;
+ },
+ {
+ set: function(data){
+ this.contents = data;
+ },
+ render: function(context, buffer){
+ // summary: Adds content onto the buffer
+ return buffer.concat(this.contents);
+ }
+ });
+
+ dd._NodeList = dojo.extend(function(/*Node[]*/ nodes){
+ // summary: Allows us to render a group of nodes
+ this.contents = nodes || [];
+ this.last = "";
+ },
+ {
+ push: function(node){
+ // summary: Add a new node to the list
+ this.contents.push(node);
+ },
+ render: function(context, buffer){
+ // summary: Adds all content onto the buffer
+ for(var i = 0; i < this.contents.length; i++){
+ buffer = this.contents[i].render(context, buffer);
+ if(!buffer) throw new Error("Template must return buffer");
+ }
+ return buffer;
+ },
+ dummyRender: function(context){
+ return this.render(context, dd.Template.prototype.getBuffer()).toString();
+ },
+ unrender: function(){ return arguments[1]; },
+ clone: function(){ return this; }
+ });
+
+ dd._VarNode = dojo.extend(function(str){
+ // summary: A node to be processed as a variable
+ this.contents = new dd._Filter(str);
+ },
+ {
+ render: function(context, buffer){
+ var str = this.contents.resolve(context);
+ return buffer.concat(str);
+ }
+ });
+
+ dd._noOpNode = new function(){
+ // summary: Adds a no-op node. Useful in custom tags
+ this.render = this.unrender = function(){ return arguments[1]; }
+ this.clone = function(){ return this; }
+ }
+
+ dd._Parser = dojo.extend(function(tokens){
+ // summary: Parser used during initialization and for tag groups.
+ this.contents = tokens;
+ },
+ {
+ i: 0,
+ parse: function(/*Array?*/ stop_at){
+ // summary: Turns tokens into nodes
+ // description: Steps into tags are they're found. Blocks use the parse object
+ // to find their closing tag (the stop_at array). stop_at is inclusive, it
+ // returns the node that matched.
+ var types = ddt.types;
+ var terminators = {};
+ stop_at = stop_at || [];
+ for(var i = 0; i < stop_at.length; i++){
+ terminators[stop_at[i]] = true;
+ }
+
+ var nodelist = new dd._NodeList();
+ while(this.i < this.contents.length){
+ token = this.contents[this.i++];
+ if(dojo.isString(token)){
+ nodelist.push(new dd._TextNode(token));
+ }else{
+ var type = token[0];
+ var text = token[1];
+ if(type == types.varr){
+ nodelist.push(new dd._VarNode(text));
+ }else if(type == types.tag){
+ if(terminators[text]){
+ --this.i;
+ return nodelist;
+ }
+ var cmd = text.split(/\s+/g);
+ if(cmd.length){
+ cmd = cmd[0];
+ var fn = ddt.getTag(cmd);
+ if(fn){
+ nodelist.push(fn(this, text));
+ }
+ }
+ }
+ }
+ }
+
+ if(stop_at.length){
+ throw new Error("Could not find closing tag(s): " + stop_at.toString());
+ }
+
+ this.contents.length = 0;
+ return nodelist;
+ },
+ next: function(){
+ // summary: Returns the next token in the list.
+ var token = this.contents[this.i++];
+ return {type: token[0], text: token[1]};
+ },
+ skipPast: function(endtag){
+ var types = ddt.types;
+ while(this.i < this.contents.length){
+ var token = this.contents[this.i++];
+ if(token[0] == types.tag && token[1] == endtag){
+ return;
+ }
+ }
+ throw new Error("Unclosed tag found when looking for " + endtag);
+ },
+ getVarNodeConstructor: function(){
+ return dd._VarNode;
+ },
+ getTextNodeConstructor: function(){
+ return dd._TextNode;
+ },
+ getTemplate: function(file){
+ return new dd.Template(file);
+ }
+ });
+
+ dd.register = {
+ _registry: {
+ attributes: [],
+ tags: [],
+ filters: []
+ },
+ get: function(/*String*/ module, /*String*/ name){
+ var registry = dd.register._registry[module + "s"];
+ for(var i = 0, entry; entry = registry[i]; i++){
+ if(dojo.isString(entry[0])){
+ if(entry[0] == name){
+ return entry;
+ }
+ }else if(name.match(entry[0])){
+ return entry;
+ }
+ }
+ },
+ getAttributeTags: function(){
+ var tags = [];
+ var registry = dd.register._registry.attributes;
+ for(var i = 0, entry; entry = registry[i]; i++){
+ if(entry.length == 3){
+ tags.push(entry);
+ }else{
+ var fn = dojo.getObject(entry[1]);
+ if(fn && dojo.isFunction(fn)){
+ entry.push(fn);
+ tags.push(entry);
+ }
+ }
+ }
+ return tags;
+ },
+ _any: function(type, base, locations){
+ for(var path in locations){
+ for(var i = 0, fn; fn = locations[path][i]; i++){
+ var key = fn;
+ if(dojo.isArray(fn)){
+ key = fn[0];
+ fn = fn[1];
+ }
+ if(dojo.isString(key)){
+ if(key.substr(0, 5) == "attr:"){
+ var attr = fn;
+ if(attr.substr(0, 5) == "attr:"){
+ attr = attr.slice(5);
+ }
+ dd.register._registry.attributes.push([attr, base + "." + path + "." + attr]);
+ }
+ key = key.toLowerCase();
+ }
+ dd.register._registry[type].push([
+ key,
+ fn,
+ base + "." + path
+ ]);
+ }
+ }
+ },
+ tags: function(/*String*/ base, /*Object*/ locations){
+ dd.register._any("tags", base, locations);
+ },
+ filters: function(/*String*/ base, /*Object*/ locations){
+ dd.register._any("filters", base, locations);
+ }
+ }
+
+ dd.register.tags("dojox.dtl.tag", {
+ "date": ["now"],
+ "logic": ["if", "for", "ifequal", "ifnotequal"],
+ "loader": ["extends", "block", "include", "load", "ssi"],
+ "misc": ["comment", "debug", "filter", "firstof", "spaceless", "templatetag", "widthratio", "with"],
+ "loop": ["cycle", "ifchanged", "regroup"]
+ });
+ dd.register.filters("dojox.dtl.filter", {
+ "dates": ["date", "time", "timesince", "timeuntil"],
+ "htmlstrings": ["escape", "linebreaks", "linebreaksbr", "removetags", "striptags"],
+ "integers": ["add", "get_digit"],
+ "lists": ["dictsort", "dictsortreversed", "first", "join", "length", "length_is", "random", "slice", "unordered_list"],
+ "logic": ["default", "default_if_none", "divisibleby", "yesno"],
+ "misc": ["filesizeformat", "pluralize", "phone2numeric", "pprint"],
+ "strings": ["addslashes", "capfirst", "center", "cut", "fix_ampersands", "floatformat", "iriencode", "linenumbers", "ljust", "lower", "make_list", "rjust", "slugify", "stringformat", "title", "truncatewords", "truncatewords_html", "upper", "urlencode", "urlize", "urlizetrunc", "wordcount", "wordwrap"]
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/contrib/data.js b/includes/js/dojox/dtl/contrib/data.js
new file mode 100644
index 0000000..5ca3aa7
--- /dev/null
+++ b/includes/js/dojox/dtl/contrib/data.js
@@ -0,0 +1,89 @@
+if(!dojo._hasResource["dojox.dtl.contrib.data"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.contrib.data"] = true;
+dojo.provide("dojox.dtl.contrib.data");
+dojo.require("dojox.dtl._base");
+
+(function(){
+ var dd = dojox.dtl;
+ var ddcd = dd.contrib.data;
+
+ ddcd._BoundItem = dojo.extend(function(item, store){
+ this.item = item;
+ this.store = store;
+ },
+ {
+ get: function(key){
+ var store = this.store;
+ var item = this.item;
+
+ if(key == "getLabel"){
+ return store.getLabel(item);
+ }else if(key == "getAttributes"){
+ return store.getAttributes(item);
+ }else if(key == "getIdentity"){
+ if(store.getIdentity){
+ return store.getIdentity(item);
+ }
+ return "Store has no identity API";
+ }else{
+ if(store.hasAttribute(item, key)){
+ var value = store.getValue(item, key);
+ return (dojo.isObject(value) && store.isItem(value)) ? new ddcd._BoundItem(value, store) : value;
+ }else if(key.slice(-1) == "s" && store.hasAttribute(item, key.slice(0, -1))){
+ return dojo.map(store.getValues(item, key.slice(0, -1)), function(value){
+ return (dojo.isObject(value) && store.isItem(value)) ? new ddcd._BoundItem(value, store) : value;
+ });
+ }
+ }
+ }
+ });
+
+ ddcd.BindDataNode = dojo.extend(function(items, store, alias){
+ this.items = new dd._Filter(items);
+ this.store = new dd._Filter(store);
+ this.alias = alias;
+ },
+ {
+ render: function(context, buffer){
+ var items = this.items.resolve(context);
+ var store = this.store.resolve(context);
+ if(!store){
+ throw new Error("data_bind didn't receive a store");
+ }
+
+ var list = [];
+ if(items){
+ for(var i = 0, item; item = items[i]; i++){
+ list.push(new ddcd._BoundItem(item, store));
+ }
+ }
+
+ context[this.alias] = list;
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return buffer;
+ },
+ clone: function(){
+ return this;
+ }
+ });
+
+ dojo.mixin(ddcd, {
+ bind_data: function(parser, text){
+ var parts = dd.text.pySplit(text);
+
+ if(parts[2] != 'to' || parts[4] != 'as' || !parts[5]){
+ throw new Error("data_bind expects the format: 'data_bind items to store as varName'");
+ }
+
+ return new ddcd.BindDataNode(parts[1], parts[3], parts[5]);
+ }
+ });
+
+ dd.register.tags("dojox.dtl.contrib", {
+ "data": ["bind_data"]
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/contrib/dijit.js b/includes/js/dojox/dtl/contrib/dijit.js
new file mode 100644
index 0000000..41caf33
--- /dev/null
+++ b/includes/js/dojox/dtl/contrib/dijit.js
@@ -0,0 +1,220 @@
+if(!dojo._hasResource["dojox.dtl.contrib.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.contrib.dijit"] = true;
+dojo.provide("dojox.dtl.contrib.dijit");
+
+dojo.require("dojox.dtl.html");
+dojo.require("dojo.parser");
+
+(function(){
+ var dd = dojox.dtl;
+ var ddcd = dd.contrib.dijit;
+
+ ddcd.AttachNode = dojo.extend(function(keys, object){
+ this._keys = keys;
+ this._object = object;
+ },
+ {
+ render: function(context, buffer){
+ if(!this._rendered){
+ this._rendered = true;
+ for(var i=0, key; key = this._keys[i]; i++){
+ context.getThis()[key] = this._object || buffer.getParent();
+ }
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ if(this._rendered){
+ this._rendered = false;
+ for(var i=0, key; key = this._keys[i]; i++){
+ if(context.getThis()[key] === (this._object || buffer.getParent())){
+ delete context.getThis()[key];
+ }
+ }
+ }
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this._keys, this._object);
+ }
+ });
+
+ ddcd.EventNode = dojo.extend(function(command, obj){
+ this._command = command;
+
+ var type, events = command.split(/\s*,\s*/);
+ var trim = dojo.trim;
+ var types = [];
+ var fns = [];
+ while(type = events.pop()){
+ if(type){
+ var fn = null;
+ if(type.indexOf(":") != -1){
+ // oh, if only JS had tuple assignment
+ var funcNameArr = type.split(":");
+ type = trim(funcNameArr[0]);
+ fn = trim(funcNameArr[1]);
+ }else{
+ type = trim(type);
+ }
+ if(!fn){
+ fn = type;
+ }
+ types.push(type);
+ fns.push(fn);
+ }
+ }
+
+ this._types = types;
+ this._fns = fns;
+ this._object = obj;
+ this._rendered = [];
+ },
+ {
+ // _clear: Boolean
+ // Make sure we kill the actual tags (onclick problems, etc)
+ _clear: false,
+ render: function(context, buffer){
+ for(var i = 0, type; type = this._types[i]; i++){
+ if(!this._clear && !this._object){
+ buffer.getParent()[type] = null;
+ }
+ var fn = this._fns[i];
+ var args;
+ if(fn.indexOf(" ") != -1){
+ if(this._rendered[i]){
+ dojo.disconnect(this._rendered[i]);
+ this._rendered[i] = false;
+ }
+ args = dojo.map(fn.split(" ").slice(1), function(item){
+ return new dd._Filter(item).resolve(context);
+ });
+ fn = fn[0];
+ }
+ if(!this._rendered[i]){
+ if(!this._object){
+ this._rendered[i] = buffer.addEvent(context, type, fn, args);
+ }else{
+ this._rendered[i] = dojo.connect(this._object, type, context.getThis(), fn);
+ }
+ }
+ }
+ this._clear = true;
+
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ while(this._rendered.length){
+ dojo.disconnect(this._rendered.pop());
+ }
+ return buffer;
+ },
+ clone: function(){
+ return new this.constructor(this._command, this._object);
+ }
+ });
+
+ function cloneNode(n1){
+ var n2 = n1.cloneNode(true);
+ if(dojo.isIE){
+ dojo.query("script", n2).forEach("item.text = this[index].text;", dojo.query("script", n1));
+ }
+ return n2;
+ }
+
+ ddcd.DojoTypeNode = dojo.extend(function(node, parsed){
+ this._node = node;
+ this._parsed = parsed;
+
+ var events = node.getAttribute("dojoAttachEvent");
+ if(events){
+ this._events = new ddcd.EventNode(dojo.trim(events));
+ }
+ var attach = node.getAttribute("dojoAttachPoint");
+ if(attach){
+ this._attach = new ddcd.AttachNode(dojo.trim(attach).split(/\s*,\s*/));
+ }
+
+ if (!parsed){
+ this._dijit = dojo.parser.instantiate([cloneNode(node)])[0];
+ }else{
+ node = cloneNode(node);
+ var old = ddcd.widgetsInTemplate;
+ ddcd.widgetsInTemplate = false;
+ this._template = new dd.HtmlTemplate(node);
+ ddcd.widgetsInTemplate = old;
+ }
+ },
+ {
+ render: function(context, buffer){
+ if(this._parsed){
+ var _buffer = new dd.HtmlBuffer();
+ this._template.render(context, _buffer);
+ var root = cloneNode(_buffer.getRootNode());
+ var div = document.createElement("div");
+ div.appendChild(root);
+ var rendered = div.innerHTML;
+ div.removeChild(root);
+ if(rendered != this._rendered){
+ this._rendered = rendered;
+ if(this._dijit){
+ this._dijit.destroyRecursive();
+ }
+ this._dijit = dojo.parser.instantiate([root])[0];
+ }
+ }
+
+ var node = this._dijit.domNode;
+
+ if(this._events){
+ this._events._object = this._dijit;
+ this._events.render(context, buffer);
+ }
+ if(this._attach){
+ this._attach._object = this._dijit;
+ this._attach.render(context, buffer);
+ }
+
+ return buffer.concat(node);
+ },
+ unrender: function(context, buffer){
+ return buffer.remove(this._dijit.domNode);
+ },
+ clone: function(){
+ return new this.constructor(this._node, this._parsed);
+ }
+ });
+
+ dojo.mixin(ddcd, {
+ widgetsInTemplate: true,
+ dojoAttachPoint: function(parser, text){
+ return new ddcd.AttachNode(dojo.trim(text).slice(16).split(/\s*,\s*/));
+ },
+ dojoAttachEvent: function(parser, text){
+ return new ddcd.EventNode(text.slice(16));
+ },
+ dojoType: function(parser, text){
+ if(ddcd.widgetsInTemplate){
+ var node = parser.swallowNode();
+ var parsed = false;
+ if(text.slice(-7) == " parsed"){
+ parsed = true;
+ node.setAttribute("dojoType", dojo.trim(text).slice(0, -7));
+ }
+ return new ddcd.DojoTypeNode(node, parsed);
+ }
+ return dd._noOpNode;
+ },
+ on: function(parser, text){
+ // summary: Associates an event type to a function (on the current widget) by name
+ var parts = text.split(" ");
+ return new ddcd.EventNode(parts[0] + ":" + parts.slice(1).join(" "));
+ }
+ });
+
+ dd.register.tags("dojox.dtl.contrib", {
+ "dijit": ["attr:dojoType", "attr:dojoAttachPoint", ["attr:attach", "dojoAttachPoint"], "attr:dojoAttachEvent", [/(attr:)?on(click|key(up))/i, "on"]]
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/contrib/html.js b/includes/js/dojox/dtl/contrib/html.js
new file mode 100644
index 0000000..260bbe2
--- /dev/null
+++ b/includes/js/dojox/dtl/contrib/html.js
@@ -0,0 +1,107 @@
+if(!dojo._hasResource["dojox.dtl.contrib.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.contrib.html"] = true;
+dojo.provide("dojox.dtl.contrib.html");
+
+dojo.require("dojox.dtl.html");
+
+(function(){
+ var dd = dojox.dtl;
+ var ddch = dd.contrib.html;
+
+ ddch.HtmlNode = dojo.extend(function(name){
+ this.contents = new dd._Filter(name);
+ this._div = document.createElement("div");
+ this._lasts = [];
+ },
+ {
+ render: function(context, buffer){
+ var text = this.contents.resolve(context);
+ if(text){
+ text = text.replace(/<(\/?script)/ig, '&lt;$1').replace(/\bon[a-z]+\s*=/ig, '');
+ if(this._rendered && this._last != text){
+ buffer = this.unrender(context, buffer);
+ }
+ this._last = text;
+
+ // This can get reset in the above tag
+ if(!this._rendered){
+ this._rendered = true;
+ var div = this._div;
+ div.innerHTML = text;
+ var children = div.childNodes;
+ while(children.length){
+ var removed = div.removeChild(children[0]);
+ this._lasts.push(removed);
+ buffer = buffer.concat(removed);
+ }
+ }
+ }
+
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ if(this._rendered){
+ this._rendered = false;
+ this._last = "";
+ for(var i = 0, node; node = this._lasts[i++];){
+ buffer = buffer.remove(node);
+ dojo._destroyElement(node);
+ }
+ this._lasts = [];
+ }
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this.contents.getExpression());
+ }
+ });
+
+ ddch.StyleNode = dojo.extend(function(styles){
+ this.contents = {};
+ this._styles = styles;
+ for(var key in styles){
+ this.contents[key] = new dd.Template(styles[key]);
+ }
+ },
+ {
+ render: function(context, buffer){
+ for(var key in this.contents){
+ dojo.style(buffer.getParent(), key, this.contents[key].render(context));
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this._styles);
+ }
+ });
+
+ dojo.mixin(ddch, {
+ html: function(parser, text){
+ var parts = text.split(" ", 2);
+ return new ddch.HtmlNode(parts[1]);
+ },
+ tstyle: function(parser, text){
+ var styles = {};
+ text = text.replace(/^tstyle\s+/, "");
+ var rules = text.split(/\s*;\s*/g);
+ for(var i = 0, rule; rule = rules[i]; i++){
+ var parts = rule.split(/\s*:\s*/g);
+ var key = parts[0];
+ var value = parts[1];
+ if(value.indexOf("{{") == 0){
+ styles[key] = value;
+ }
+ }
+ return new ddch.StyleNode(styles);
+ }
+ });
+
+ dd.register.tags("dojox.dtl.contrib", {
+ "html": ["html", "attr:tstyle"]
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/contrib/objects.js b/includes/js/dojox/dtl/contrib/objects.js
new file mode 100644
index 0000000..d29c0df
--- /dev/null
+++ b/includes/js/dojox/dtl/contrib/objects.js
@@ -0,0 +1,15 @@
+if(!dojo._hasResource["dojox.dtl.contrib.objects"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.contrib.objects"] = true;
+dojo.provide("dojox.dtl.contrib.objects");
+
+dojo.mixin(dojox.dtl.contrib.objects, {
+ key: function(value, arg){
+ return value[arg];
+ }
+});
+
+dojox.dtl.register.filters("dojox.dtl.contrib", {
+ "objects": ["key"]
+});
+
+}
diff --git a/includes/js/dojox/dtl/demos/demo_Animation.html b/includes/js/dojox/dtl/demos/demo_Animation.html
new file mode 100644
index 0000000..1a5e278
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Animation.html
@@ -0,0 +1,45 @@
+<html>
+ <head>
+ <title>Testing dojox.dtl using animation to change attributes</title>
+ <script src="../../../dojo/dojo.js" djConfig="parseOnLoad: true, usePlainJson: true"></script>
+ <script>
+ dojo.require("dijit._Widget");
+ dojo.require("dojox.dtl._HtmlTemplated");
+
+ dojo.declare("demo.Animation", [dijit._Widget, dojox.dtl._HtmlTemplated],
+ {
+ buffer: 0, // Note: Sensitivity is 0 by default, but this is to emphasize we're not doing any buffering
+ templatePath: dojo.moduleUrl("dojox.dtl.demos.templates", "animation.html"),
+ constructor: function(props, node){
+ console.debug("constructor");
+ this.x = 0;
+ this.y = 0;
+ },
+ postCreate: function(){
+ var anim = new dojo._Animation({
+ curve: [0, 300],
+ rate: 10,
+ duration: 5000,
+ easing: dojo._defaultEasing
+ });
+ dojo.connect(anim, "onAnimate", this, "_reDraw");
+ anim.play();
+ },
+ _reDraw: function(obj){
+ this.x = obj;
+ this.y = Math.sqrt(obj) * 10;
+
+ dojo.style(this.blue, "left", this.x);
+ dojo.style(this.blue, "top", this.y + 10);
+
+ this.render();
+ }
+ });
+
+ dojo.require("dojo.parser");
+ </script>
+ </head>
+ <body>
+ <div dojoType="demo.Animation" />
+ </body>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/demo_Blog.html b/includes/js/dojox/dtl/demos/demo_Blog.html
new file mode 100644
index 0000000..c9bd990
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Blog.html
@@ -0,0 +1,96 @@
+<html>
+ <head>
+ <title>Testing dojox.dtl using a blog example</title>
+ <script src="../../../dojo/dojo.js" djConfig="usePlainJson: true, parseOnLoad: true"></script>
+ <script>
+ dojo.require("dijit._Widget");
+ dojo.require("dojox.dtl._HtmlTemplated");
+ dojo.require("dojo.parser");
+
+ dojo.declare("demo.Blog", [dijit._Widget, dojox.dtl._HtmlTemplated],
+ {
+ buffer: dojox.dtl.render.html.sensitivity.NODE,
+ templatePath: dojo.moduleUrl("dojox.dtl.demos.templates", "blog_list.html"),
+ base: {
+ url: dojo.moduleUrl("dojox.dtl.demos.templates", "blog_base.html"),
+ shared: true
+ },
+ constructor: function(props, node){
+ this.list = false;
+ this.blogs = {};
+ this.pages = {};
+ },
+ postCreate: function(){
+ if(!this.list){
+ dojo.xhrGet({
+ url: dojo.moduleUrl("dojox.dtl.demos.json.blog", "get_blog_list.json"),
+ handleAs: "json"
+ }).addCallback(this, "_loadList");
+ }
+ },
+ _showList: function(obj){
+ this.title = "Blog Posts";
+ this.setTemplate(this.templatePath);
+ },
+ _showDetail: function(obj){
+ var key = obj.target.className.substring(5);
+
+ if(this.blogs[key]){
+ this.title = "Blog Post";
+ this.blog = this.blogs[key];
+ this.blog.title = this.blog_list[key].title;
+ this.setTemplate(dojo.moduleUrl("dojox.dtl.demos.templates", "blog_detail.html"));
+ }else{
+ dojo.xhrGet({
+ url: dojo.moduleUrl("dojox.dtl.demos.json.blog", "get_blog_" + key + ".json"),
+ handleAs: "json",
+ load: function(data){
+ data.key = key;
+ return data;
+ }
+ }).addCallback(this, "_loadDetail");
+ }
+ },
+ _showPage: function(obj){
+ var key = obj.target.className.substring(5);
+
+ if(this.pages[key]){
+ this.title = this.pages[key].title;
+ this.body = this.pages[key].body;
+ this.setTemplate(dojo.moduleUrl("dojox.dtl.demos.templates", "blog_page.html"));
+ }else{
+ dojo.xhrGet({
+ url: dojo.moduleUrl("dojox.dtl.demos.json.blog", "get_page_" + key + ".json"),
+ handleAs: "json",
+ load: function(data){
+ data.key = key;
+ return data;
+ }
+ }).addCallback(this, "_loadPage");
+ }
+ },
+ _loadList: function(data){
+ this.title = "Blog Posts";
+ dojo.mixin(this, data);
+ this.render();
+ },
+ _loadDetail: function(data){
+ data.date = new Date(data.date);
+ this.blogs[data.key] = data;
+ this.title = "Blog Post";
+ this.blog = data;
+ this.blog.title = this.blog_list[data.key].title;
+ this.setTemplate(dojo.moduleUrl("dojox.dtl.demos.templates", "blog_detail.html"));
+ },
+ _loadPage: function(data){
+ this.pages[data.key] = data;
+ dojo.mixin(this, data);
+ this.setTemplate(dojo.moduleUrl("dojox.dtl.demos.templates", "blog_page.html"));
+ }
+ });
+ </script>
+ </head>
+ <body>
+ <div dojoType="demo.Blog" />
+ </body>
+</html>
diff --git a/includes/js/dojox/dtl/demos/demo_Data.html b/includes/js/dojox/dtl/demos/demo_Data.html
new file mode 100644
index 0000000..93bb76f
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Data.html
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <title>Demo using the dojo.data bind_data tag</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../../dijit/dijit.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl._Templated");
+ dojo.require("dojox.data.FlickrRestStore");
+ dojo.require("dojo.parser");
+
+ dojo.declare("demo.Gallery", [dijit._Widget, dojox.dtl._Templated], {
+ templatePath: dojo.moduleUrl("dojox.dtl.demos.templates", "gallery.html"),
+ store: new dojox.data.FlickrRestStore(),
+ selectThumbnail: function(e){
+ this.selected = e.target.className;
+ this.render();
+ },
+ keyUp: function(e){
+ if(e.keyCode == dojo.keys.ENTER){
+ var search = e.target.value;
+ var query = {
+ query: {
+ userid: "44153025@N00",
+ apikey: "8c6803164dbc395fb7131c9d54843627",
+ sort: [
+ {
+ attribute: "interestingness",
+ descending: true
+ }
+ ],
+ tags: search.split(/\s*,\s*/g),
+ tag_mode: "any"
+ },
+ start: 0,
+ count: 10,
+ onBegin: dojo.hitch(this, function(total){
+ console.debug(total);
+ this._maxPhotos = total;
+ }),
+ onComplete: dojo.hitch(this, function(items, request){
+ console.debug(items);
+ if(items && items.length) {
+ this.items = items;
+ this.render();
+ }
+ })
+ };
+ this.store.fetch(query);
+ }
+ }
+ });
+ </script>
+ <body>
+ <div dojoType="demo.Gallery"></div>
+ </body>
+ </head>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/demo_Dijitless.html b/includes/js/dojox/dtl/demos/demo_Dijitless.html
new file mode 100644
index 0000000..2aaceaa
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Dijitless.html
@@ -0,0 +1,50 @@
+<html>
+ <head>
+ <title>Demo using dojox.dtl._HtmlTemplated without Dijit</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl.html");
+ dojo.require("dojox.dtl.render.html");
+ dojo.require("dojox.dtl.Context");
+
+ dojo.addOnLoad(function(){
+ var context = new dojox.dtl.Context({
+ items: ["apple", "banana", "orange"]
+ });
+
+ var template = new dojox.dtl.HtmlTemplate("<ul><!--{% for item in items %}--><li><!--{{ item }}--></li><!--{% endfor %}--></ul>");
+ // Render it plain
+ var node = template.render(context).getRootNode();
+ dojo.body().appendChild(node);
+
+ // Now show an example of how hard it is to manage stuff if the root node changes
+ var template2 = new dojox.dtl.HtmlTemplate("<!--{% ifequal items.length 3 %}--><ul><!--{% for item in items %}--><li><!--{{ item }}--></li><!--{% endfor %}--></ul>{% else %}<div>More than 3 items!</div>{% endifequal %}");
+ // Render it plain
+ var node2 = template2.render(context).getRootNode();
+ dojo.body().appendChild(node2);
+
+ // Now show how the HTML Render object makes this easier
+ var renderer = new dojox.dtl.render.html.Render(dojo.byId("attach"), new dojox.dtl.HtmlTemplate("<!--{% ifequal items.length 3 %}--><ul><!--{% for item in items reversed %}--><li><!--{{ item }}--></li><!--{% endfor %}--></ul>{% else %}<div>More than 3 items!</div>{% endifequal %}"));
+ renderer.render(context);
+
+ // Now re-render and break template2
+ setTimeout(function(){
+ context.items.push("guava");
+ template.render(context);
+ template2.render(context);
+ renderer.render(context);
+
+ // This is what has to be done to fix template2
+ setTimeout(function(){
+ var frag = template2.render(context).getRootNode();
+ node2.parentNode.replaceChild(frag, node2);
+ }, 3000);
+ }, 3000);
+ });
+ </script>
+ </head>
+ <body>
+ <div id="attach"></div>
+ </body>
+</html>
diff --git a/includes/js/dojox/dtl/demos/demo_Events.html b/includes/js/dojox/dtl/demos/demo_Events.html
new file mode 100644
index 0000000..aa3da46
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Events.html
@@ -0,0 +1,46 @@
+<html>
+ <head>
+ <title>Demo using dojox.dtl._Templated</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../../dijit/dijit.js"></script>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ </style>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl._HtmlTemplated");
+ dojo.require("dijit.form.Button");
+
+ dojo.declare("Fruit", [dijit._Widget, dojox.dtl._HtmlTemplated], {
+ widgetsInTemplate: true,
+ items: ["apple", "banana", "orange"],
+ keyUp: function(e){
+ if((e.type == "click" || e.keyCode == dojo.keys.ENTER) && this.input.value){
+ var i = dojo.indexOf(this.items, this.input.value);
+ if(i != -1){
+ this.items.splice(i, 1);
+ }else{
+ this.items.push(this.input.value);
+ }
+ this.input.value = "";
+ this.render();
+ }
+ },
+ postCreate: function(){
+ this.render();
+ dojo.connect(this.button, "onClick", this, "keyUp");
+ },
+ debug: function(e, verb, fruit){
+ console.debug("You " + verb + " a:", fruit);
+ },
+ // Note, the load tag here is superfluous, since _HtmlTemplate has a dojo.require for it.
+ templateString: '<!--{% load dojox.dtl.contrib.dijit %}--><div><input dojoAttachEvent="onkeyup: keyUp" dojoAttachPoint="input"> <button dojoType="dijit.form.Button" dojoAttachPoint="button">Add/Remove Item</button><ul><!--{% for item in items %}--><li onclick="debug \'ate\' item"><!--{{ item }}--></li><!--{% endfor %}--></ul></div>'
+ });
+
+ dojo.require("dojo.parser");
+ </script>
+ <body class="tundra">
+ <div dojoType="Fruit"></div>
+ </body>
+ </head>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/demo_HtmlTemplated.html b/includes/js/dojox/dtl/demos/demo_HtmlTemplated.html
new file mode 100644
index 0000000..71dabe4
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_HtmlTemplated.html
@@ -0,0 +1,40 @@
+<html>
+ <head>
+ <title>Demo using dojox.dtl._HtmlTemplated</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../../dijit/dijit.js"></script>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+ </style>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl._HtmlTemplated");
+ dojo.require("dijit.form.Button");
+
+ dojo.declare("Fruit", [dijit._Widget, dojox.dtl._HtmlTemplated], {
+ widgetsInTemplate: true,
+ items: ["apple", "banana", "orange"],
+ keyUp: function(e){
+ if((e.type == "click" || e.keyCode == dojo.keys.ENTER) && this.input.value){
+ console.debug(this.button);
+ var i = dojo.indexOf(this.items, this.input.value);
+ if(i != -1){
+ this.items.splice(i, 1);
+ }else{
+ this.items.push(this.input.value);
+ }
+ this.input.value = "";
+ this.render();
+ }
+ },
+ // Note, the load tag here is superfluous, since _HtmlTemplate has a dojo.require for it.
+ templateString: '<!--{% load dojox.dtl.contrib.dijit %}--><div><input dojoAttachEvent="onkeyup: keyUp" dojoAttachPoint="input"> <button dojoType="dijit.form.Button" dojoAttachPoint="button" dojoAttachEvent="onClick: keyUp">Add/Remove Item</button><ul><!--{% for item in items %}--><li><button dojoType="dijit.form.Button parsed" title="Fruit: {{ item }}"><!--{{ item }}--><script type="dojo/connect" event="onClick" args="e">console.debug("You clicked", this.containerNode.innerHTML);</' + 'script></button></li><!--{% endfor %}--></ul></div>'
+ });
+
+ dojo.require("dojo.parser");
+ </script>
+ <body class="tundra">
+ <div dojoType="Fruit" id="dtl"></div>
+ </body>
+ </head>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/demo_Inline.html b/includes/js/dojox/dtl/demos/demo_Inline.html
new file mode 100644
index 0000000..6e17d8e
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Inline.html
@@ -0,0 +1,48 @@
+<html>
+ <head>
+ <title>Demo using dojox.dtl._HtmlTemplated inline in DOM</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl.html");
+ dojo.require("dojox.dtl.Context");
+
+ dojo.addOnLoad(function(){
+ // Create a template from our first node (still in DOM)
+ var template = new dojox.dtl.HtmlTemplate("template");
+ var context = new dojox.dtl.Context({
+ items: ["apple", "banana", "orange"]
+ });
+ // Render it first without initial item list
+ template.render(context);
+
+ // Create a template with our second node (removed from DOM)
+ var node = dojo.byId("template2");
+ node.parentNode.removeChild(node);
+ var template2 = new dojox.dtl.HtmlTemplate(node);
+ // The render function returns a buffer, which has the getRootNode function
+ dojo.body().appendChild(template2.render(context).getRootNode());
+
+ // The re-render each with a new item
+ setTimeout(function(){
+ context.items.push("guava");
+ template.render(context);
+ template2.render(context);
+ }, 3000);
+ });
+ </script>
+ </head>
+ <body>
+ <ul id="template">
+ {% for item in items %}
+ <li>{{ item }}</li>
+ {% endfor %}
+ </ul>
+
+ <ul id="template2">
+ {% for item in items reversed %}
+ <li>{{ item }}</li>
+ {% endfor %}
+ </ul>
+ </body>
+</html>
diff --git a/includes/js/dojox/dtl/demos/demo_NodeList.html b/includes/js/dojox/dtl/demos/demo_NodeList.html
new file mode 100644
index 0000000..d1ab0a8
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_NodeList.html
@@ -0,0 +1,37 @@
+<html>
+ <head>
+ <title>Demo using dojox.dtl._Templated</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl.ext-dojo.NodeList");
+ dojo.require("dojox.dtl.Context");
+
+ dojo.addOnLoad(function(){
+ // First, look at the NodeList extension
+ dojo.query(".fruit").dtl(dojo.moduleUrl("dojox.dtl.demos.templates", "nodelist.html"), { items: ["apple", "banana", "pear"] });
+
+ dojo.query(".fruit2").dtl("<div><ul>{% for item in items %}<li>{{ item }}</li>{% endfor %}</ul></div", { items: ["apple", "banana", "pear"] });
+
+ // Now, create a real template object
+ var tpl = new dojox.dtl.Template(dojo.moduleUrl("dojox.dtl.demos.templates", "nodelist.html"));
+
+ // And test its update function with a dojo.query
+ tpl.update(dojo.query(".update"), dojo.moduleUrl("dojox.dtl.demos.json", "fruit.json"));
+
+ setTimeout(function(){
+ // And now test it with an ID reference
+ tpl.update("updateId", dojo.moduleUrl("dojox.dtl.demos.json", "morefruit.json"));
+ // And throw in a standard rendering just for fun
+ dojo.byId("updateId2").innerHTML = tpl.render(new dojox.dtl.Context({ items: ["pineapple", "orange", "tomato"] }));
+ }, 5000);
+ });
+ </script>
+ </head>
+ <body>
+ <div class="fruit"></div>
+ <div class="fruit2"></div>
+ <div class="update" id="updateId"></div>
+ <div class="update" id="updateId2"></div>
+ </body>
+</html>
diff --git a/includes/js/dojox/dtl/demos/demo_Table.html b/includes/js/dojox/dtl/demos/demo_Table.html
new file mode 100644
index 0000000..56dc8ac
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Table.html
@@ -0,0 +1,4072 @@
+<html>
+ <head>
+ <title>Demo to show a massive nested for loop to render a table</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../../dijit/dijit.js"></script>
+ <style type="text/css">
+ @import "../../../dijit/themes/tundra/tundra.css";
+
+ table {
+ border-collapse: collapse;
+ }
+ th {
+ background-color: #ccf;
+ }
+ th, td {
+ border: 1px solid #aaa;
+ padding: 2px 15px;
+ }
+ tr.even td {
+ background-color: #ffc;
+ }
+ </style>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl._HtmlTemplated");
+ dojo.require("dojox.dtl.tag.logic");
+ dojo.require("dojox.dtl.tag.loop");
+ dojo.require("dojox.dtl.filter.lists");
+
+ dojo.declare("demo.Table", [dijit._Widget, dojox.dtl._HtmlTemplated], {
+ pos: 0,
+ postCreate: function(){
+ this.ths = dojo.query("th", this.domNode).map(function(item){
+ return item.innerHTML;
+ });
+ this.trs = dojo.query("tbody tr", this.domNode).map(function(item){
+ return dojo.query("td", item).map(function(item){
+ return item.innerHTML;
+ });
+ });
+ console.time("render1");
+ this.render();
+ console.timeEnd("render1");
+ },
+ sortColumn: function(e){
+ this.pos = dojo.indexOf(this.ths, e.target.innerHTML);
+ console.time("render2");
+ this.render();
+ console.timeEnd("render2");
+ },
+ templateString: '<table><thead><tr><!--{% for th in ths %}--><th dojoAttachEvent="onclick: sortColumn"><!--{{ th }}--></th><!--{% endfor %}--></tr></thead><tbody><!--{% for tr in trs|dictsort:pos %}--><tr class="{% cycle \'odd\' \'even\' %}"><!--{% for td in tr %}--><td><!--{{ td }}--></td><!--{% endfor %}--></tr><!--{% endfor %}--></tbody></table>'
+ });
+
+ dojo.require("dojo.parser");
+ </script>
+ <body class="tundra">
+ <table dojoType="demo.Table" style="display: none;">
+ <thead>
+ <tr>
+ <th>Index</th>
+ <th>Numeric</th>
+ <th>Text</th>
+ <th>Currency</th>
+ <th>Date</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>0</td>
+ <td>158.9</td>
+ <td>Bill</td>
+ <td>$22.44</td>
+
+ <td>2008-12-28</td>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>690.4</td>
+ <td>Joe</td>
+ <td>$3.03</td>
+
+ <td>2009-07-03</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>843</td>
+ <td>Bob</td>
+ <td>$11.14</td>
+
+ <td>2010-09-30</td>
+ </tr>
+ <tr>
+ <td>3</td>
+ <td>57.8</td>
+ <td>Matt</td>
+ <td>$70.64</td>
+
+ <td>2009-12-16</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>494.6</td>
+ <td>Mark</td>
+ <td>$9.13</td>
+
+ <td>2010-05-11</td>
+ </tr>
+ <tr>
+ <td>5</td>
+ <td>766.3</td>
+ <td>Tom</td>
+ <td>$55.34</td>
+
+ <td>2008-03-10</td>
+ </tr>
+ <tr>
+ <td>6</td>
+ <td>699.3</td>
+ <td>Jake</td>
+ <td>$26.24</td>
+
+ <td>2008-11-26</td>
+ </tr>
+ <tr>
+ <td>7</td>
+ <td>487.8</td>
+ <td>Greg</td>
+ <td>$72.94</td>
+
+ <td>2010-06-23</td>
+ </tr>
+ <tr>
+ <td>8</td>
+ <td>786.2</td>
+ <td>Adam</td>
+ <td>$34.64</td>
+
+ <td>2008-09-19</td>
+ </tr>
+ <tr>
+ <td>9</td>
+ <td>188.6</td>
+ <td>Steve</td>
+ <td>$6.33</td>
+
+ <td>2009-01-01</td>
+ </tr>
+ <tr>
+ <td>10</td>
+ <td>898.4</td>
+ <td>George</td>
+ <td>$22.24</td>
+
+ <td>2009-09-18</td>
+ </tr>
+ <tr>
+ <td>11</td>
+ <td>222.2</td>
+ <td>John</td>
+ <td>$91.24</td>
+
+ <td>2009-10-23</td>
+ </tr>
+ <tr>
+ <td>12</td>
+ <td>707.9</td>
+ <td>Phil</td>
+ <td>$75.54</td>
+
+ <td>2010-02-28</td>
+ </tr>
+ <tr>
+ <td>13</td>
+ <td>585.5</td>
+ <td>Jack</td>
+ <td>$81.34</td>
+
+ <td>2009-03-24</td>
+ </tr>
+ <tr>
+ <td>14</td>
+ <td>213.8</td>
+ <td>Paul</td>
+ <td>$30.74</td>
+
+ <td>2009-07-08</td>
+ </tr>
+ <tr>
+ <td>15</td>
+ <td>968.5</td>
+ <td>Rob</td>
+ <td>$7.33</td>
+
+ <td>2008-02-06</td>
+ </tr>
+ <tr>
+ <td>16</td>
+ <td>39.3</td>
+ <td>Walt</td>
+ <td>$77.34</td>
+
+ <td>2008-12-05</td>
+ </tr>
+ <tr>
+ <td>17</td>
+ <td>335.7</td>
+ <td>Nathan</td>
+ <td>$26.14</td>
+
+ <td>2008-01-27</td>
+ </tr>
+ <tr>
+ <td>18</td>
+ <td>127.6</td>
+ <td>Dan</td>
+ <td>$4.73</td>
+
+ <td>2009-03-03</td>
+ </tr>
+ <tr>
+ <td>19</td>
+ <td>365.3</td>
+ <td>Jeff</td>
+ <td>$23.54</td>
+
+ <td>2009-05-15</td>
+ </tr>
+ <tr>
+ <td>20</td>
+ <td>692.9</td>
+ <td>Bill</td>
+ <td>$13.34</td>
+
+ <td>2010-01-26</td>
+ </tr>
+ <tr>
+ <td>21</td>
+ <td>244.9</td>
+ <td>Joe</td>
+ <td>$35.64</td>
+
+ <td>2009-10-16</td>
+ </tr>
+ <tr>
+ <td>22</td>
+ <td>827</td>
+ <td>Bob</td>
+ <td>$6.33</td>
+
+ <td>2009-01-06</td>
+ </tr>
+ <tr>
+ <td>23</td>
+ <td>519.6</td>
+ <td>Matt</td>
+ <td>$64.94</td>
+
+ <td>2008-06-03</td>
+ </tr>
+ <tr>
+ <td>24</td>
+ <td>917.8</td>
+ <td>Mark</td>
+ <td>$86.34</td>
+
+ <td>2009-05-24</td>
+ </tr>
+ <tr>
+ <td>25</td>
+ <td>407.1</td>
+ <td>Tom</td>
+ <td>$83.14</td>
+
+ <td>2009-08-17</td>
+ </tr>
+ <tr>
+ <td>26</td>
+ <td>449.3</td>
+ <td>Jake</td>
+ <td>$87.04</td>
+
+ <td>2008-11-27</td>
+ </tr>
+ <tr>
+ <td>27</td>
+ <td>753.5</td>
+ <td>Greg</td>
+ <td>$20.64</td>
+
+ <td>2009-09-25</td>
+ </tr>
+ <tr>
+ <td>28</td>
+ <td>787</td>
+ <td>Adam</td>
+ <td>$33.44</td>
+
+ <td>2009-11-18</td>
+ </tr>
+ <tr>
+ <td>29</td>
+ <td>166.9</td>
+ <td>Steve</td>
+ <td>$69.94</td>
+
+ <td>2010-08-17</td>
+ </tr>
+ <tr>
+ <td>30</td>
+ <td>609.6</td>
+ <td>George</td>
+ <td>$39.24</td>
+
+ <td>2011-01-18</td>
+ </tr>
+ <tr>
+ <td>31</td>
+ <td>274</td>
+ <td>John</td>
+ <td>$63.64</td>
+
+ <td>2009-01-02</td>
+ </tr>
+ <tr>
+ <td>32</td>
+ <td>850.3</td>
+ <td>Phil</td>
+ <td>$46.34</td>
+
+ <td>2009-03-17</td>
+ </tr>
+ <tr>
+ <td>33</td>
+ <td>181.4</td>
+ <td>Jack</td>
+ <td>$98.34</td>
+
+ <td>2008-02-04</td>
+ </tr>
+ <tr>
+ <td>34</td>
+ <td>325.3</td>
+ <td>Paul</td>
+ <td>$90.14</td>
+
+ <td>2010-10-30</td>
+ </tr>
+ <tr>
+ <td>35</td>
+ <td>776.3</td>
+ <td>Rob</td>
+ <td>$30.84</td>
+
+ <td>2010-04-17</td>
+ </tr>
+ <tr>
+ <td>36</td>
+ <td>300.8</td>
+ <td>Walt</td>
+ <td>$75.74</td>
+
+ <td>2009-11-18</td>
+ </tr>
+ <tr>
+ <td>37</td>
+ <td>598</td>
+ <td>Nathan</td>
+ <td>$51.04</td>
+
+ <td>2010-07-15</td>
+ </tr>
+ <tr>
+ <td>38</td>
+ <td>155.6</td>
+ <td>Dan</td>
+ <td>$29.74</td>
+
+ <td>2008-06-04</td>
+ </tr>
+ <tr>
+ <td>39</td>
+ <td>759.8</td>
+ <td>Jeff</td>
+ <td>$46.44</td>
+
+ <td>2010-08-21</td>
+ </tr>
+ <tr>
+ <td>40</td>
+ <td>599.2</td>
+ <td>Bill</td>
+ <td>$7.43</td>
+
+ <td>2008-09-16</td>
+ </tr>
+ <tr>
+ <td>41</td>
+ <td>571.9</td>
+ <td>Joe</td>
+ <td>$34.84</td>
+
+ <td>2010-09-23</td>
+ </tr>
+ <tr>
+ <td>42</td>
+ <td>900.3</td>
+ <td>Bob</td>
+ <td>$19.84</td>
+
+ <td>2009-01-09</td>
+ </tr>
+ <tr>
+ <td>43</td>
+ <td>292.2</td>
+ <td>Matt</td>
+ <td>$37.94</td>
+
+ <td>2008-12-21</td>
+ </tr>
+ <tr>
+ <td>44</td>
+ <td>333</td>
+ <td>Mark</td>
+ <td>$70.54</td>
+
+ <td>2008-08-28</td>
+ </tr>
+ <tr>
+ <td>45</td>
+ <td>236.4</td>
+ <td>Tom</td>
+ <td>$48.14</td>
+
+ <td>2009-08-19</td>
+ </tr>
+ <tr>
+ <td>46</td>
+ <td>970.9</td>
+ <td>Jake</td>
+ <td>$78.24</td>
+
+ <td>2008-11-10</td>
+ </tr>
+ <tr>
+ <td>47</td>
+ <td>575.8</td>
+ <td>Greg</td>
+ <td>$37.94</td>
+
+ <td>2010-06-24</td>
+ </tr>
+ <tr>
+ <td>48</td>
+ <td>386.7</td>
+ <td>Adam</td>
+ <td>$53.54</td>
+
+ <td>2008-04-02</td>
+ </tr>
+ <tr>
+ <td>49</td>
+ <td>531.1</td>
+ <td>Steve</td>
+ <td>$29.54</td>
+
+ <td>2009-09-21</td>
+ </tr>
+ <tr>
+ <td>50</td>
+ <td>374.3</td>
+ <td>George</td>
+ <td>$89.44</td>
+
+ <td>2009-12-15</td>
+ </tr>
+ <tr>
+ <td>51</td>
+ <td>609.1</td>
+ <td>John</td>
+ <td>$46.64</td>
+
+ <td>2011-01-22</td>
+ </tr>
+ <tr>
+ <td>52</td>
+ <td>480.3</td>
+ <td>Phil</td>
+ <td>$36.64</td>
+
+ <td>2008-07-07</td>
+ </tr>
+ <tr>
+ <td>53</td>
+ <td>814.8</td>
+ <td>Jack</td>
+ <td>$65.84</td>
+
+ <td>2009-09-19</td>
+ </tr>
+ <tr>
+ <td>54</td>
+ <td>132.2</td>
+ <td>Paul</td>
+ <td>$99.14</td>
+
+ <td>2008-10-12</td>
+ </tr>
+ <tr>
+ <td>55</td>
+ <td>350.1</td>
+ <td>Rob</td>
+ <td>$22.84</td>
+
+ <td>2010-04-22</td>
+ </tr>
+ <tr>
+ <td>56</td>
+ <td>875.7</td>
+ <td>Walt</td>
+ <td>$19.84</td>
+
+ <td>2009-08-12</td>
+ </tr>
+ <tr>
+ <td>57</td>
+ <td>158.1</td>
+ <td>Nathan</td>
+ <td>$77.44</td>
+
+ <td>2010-10-25</td>
+ </tr>
+ <tr>
+ <td>58</td>
+ <td>950.9</td>
+ <td>Dan</td>
+ <td>$16.14</td>
+
+ <td>2009-05-05</td>
+ </tr>
+ <tr>
+ <td>59</td>
+ <td>41.1</td>
+ <td>Jeff</td>
+ <td>$69.24</td>
+
+ <td>2010-04-11</td>
+ </tr>
+ <tr>
+ <td>60</td>
+ <td>595.4</td>
+ <td>Bill</td>
+ <td>$6.63</td>
+
+ <td>2009-12-09</td>
+ </tr>
+ <tr>
+ <td>61</td>
+ <td>223.4</td>
+ <td>Joe</td>
+ <td>$67.54</td>
+
+ <td>2008-03-30</td>
+ </tr>
+ <tr>
+ <td>62</td>
+ <td>199.2</td>
+ <td>Bob</td>
+ <td>$15.64</td>
+
+ <td>2009-05-28</td>
+ </tr>
+ <tr>
+ <td>63</td>
+ <td>372.8</td>
+ <td>Matt</td>
+ <td>$97.04</td>
+
+ <td>2008-04-28</td>
+ </tr>
+ <tr>
+ <td>64</td>
+ <td>925.7</td>
+ <td>Mark</td>
+ <td>$10.24</td>
+
+ <td>2008-04-17</td>
+ </tr>
+ <tr>
+ <td>65</td>
+ <td>183.1</td>
+ <td>Tom</td>
+ <td>$45.34</td>
+
+ <td>2009-01-05</td>
+ </tr>
+ <tr>
+ <td>66</td>
+ <td>921.2</td>
+ <td>Jake</td>
+ <td>$32.84</td>
+
+ <td>2009-08-23</td>
+ </tr>
+ <tr>
+ <td>67</td>
+ <td>440.8</td>
+ <td>Greg</td>
+ <td>$48.64</td>
+
+ <td>2008-12-04</td>
+ </tr>
+ <tr>
+ <td>68</td>
+ <td>339.8</td>
+ <td>Adam</td>
+ <td>$43.74</td>
+
+ <td>2009-06-08</td>
+ </tr>
+ <tr>
+ <td>69</td>
+ <td>773.7</td>
+ <td>Steve</td>
+ <td>$47.84</td>
+
+ <td>2008-06-17</td>
+ </tr>
+ <tr>
+ <td>70</td>
+ <td>502.3</td>
+ <td>George</td>
+ <td>$7.33</td>
+
+ <td>2008-09-01</td>
+ </tr>
+ <tr>
+ <td>71</td>
+ <td>124.8</td>
+ <td>John</td>
+ <td>$29.74</td>
+
+ <td>2010-10-22</td>
+ </tr>
+ <tr>
+ <td>72</td>
+ <td>213</td>
+ <td>Phil</td>
+ <td>$49.64</td>
+
+ <td>2008-02-18</td>
+ </tr>
+ <tr>
+ <td>73</td>
+ <td>667.3</td>
+ <td>Jack</td>
+ <td>$86.94</td>
+
+ <td>2008-01-14</td>
+ </tr>
+ <tr>
+ <td>74</td>
+ <td>779.8</td>
+ <td>Paul</td>
+ <td>$79.44</td>
+
+ <td>2008-05-12</td>
+ </tr>
+ <tr>
+ <td>75</td>
+ <td>883.3</td>
+ <td>Rob</td>
+ <td>$97.74</td>
+
+ <td>2009-10-17</td>
+ </tr>
+ <tr>
+ <td>76</td>
+ <td>214.4</td>
+ <td>Walt</td>
+ <td>$89.94</td>
+
+ <td>2010-11-01</td>
+ </tr>
+ <tr>
+ <td>77</td>
+ <td>743.7</td>
+ <td>Nathan</td>
+ <td>$33.94</td>
+
+ <td>2009-03-16</td>
+ </tr>
+ <tr>
+ <td>78</td>
+ <td>47</td>
+ <td>Dan</td>
+ <td>$67.94</td>
+
+ <td>2010-08-04</td>
+ </tr>
+ <tr>
+ <td>79</td>
+ <td>511</td>
+ <td>Jeff</td>
+ <td>$45.34</td>
+
+ <td>2008-12-08</td>
+ </tr>
+ <tr>
+ <td>80</td>
+ <td>666.7</td>
+ <td>Bill</td>
+ <td>$95.54</td>
+
+ <td>2009-03-03</td>
+ </tr>
+ <tr>
+ <td>81</td>
+ <td>888.5</td>
+ <td>Joe</td>
+ <td>$8.03</td>
+
+ <td>2010-02-09</td>
+ </tr>
+ <tr>
+ <td>82</td>
+ <td>785.4</td>
+ <td>Bob</td>
+ <td>$29.34</td>
+
+ <td>2008-07-06</td>
+ </tr>
+ <tr>
+ <td>83</td>
+ <td>837.7</td>
+ <td>Matt</td>
+ <td>$96.04</td>
+
+ <td>2008-02-05</td>
+ </tr>
+ <tr>
+ <td>84</td>
+ <td>860.2</td>
+ <td>Mark</td>
+ <td>$74.04</td>
+
+ <td>2010-08-12</td>
+ </tr>
+ <tr>
+ <td>85</td>
+ <td>985</td>
+ <td>Tom</td>
+ <td>$62.34</td>
+
+ <td>2010-07-17</td>
+ </tr>
+ <tr>
+ <td>86</td>
+ <td>562.3</td>
+ <td>Jake</td>
+ <td>$83.74</td>
+
+ <td>2010-03-21</td>
+ </tr>
+ <tr>
+ <td>87</td>
+ <td>467.6</td>
+ <td>Greg</td>
+ <td>$58.14</td>
+
+ <td>2008-02-16</td>
+ </tr>
+ <tr>
+ <td>88</td>
+ <td>859</td>
+ <td>Adam</td>
+ <td>$62.84</td>
+
+ <td>2010-04-12</td>
+ </tr>
+ <tr>
+ <td>89</td>
+ <td>687.5</td>
+ <td>Steve</td>
+ <td>$13.94</td>
+
+ <td>2008-07-17</td>
+ </tr>
+ <tr>
+ <td>90</td>
+ <td>993.9</td>
+ <td>George</td>
+ <td>$80.54</td>
+
+ <td>2008-05-26</td>
+ </tr>
+ <tr>
+ <td>91</td>
+ <td>373.8</td>
+ <td>John</td>
+ <td>$69.44</td>
+
+ <td>2008-08-26</td>
+ </tr>
+ <tr>
+ <td>92</td>
+ <td>50.4</td>
+ <td>Phil</td>
+ <td>$47.94</td>
+
+ <td>2009-07-30</td>
+ </tr>
+ <tr>
+ <td>93</td>
+ <td>222.8</td>
+ <td>Jack</td>
+ <td>$31.74</td>
+
+ <td>2009-06-14</td>
+ </tr>
+ <tr>
+ <td>94</td>
+ <td>263.9</td>
+ <td>Paul</td>
+ <td>$17.74</td>
+
+ <td>2008-08-16</td>
+ </tr>
+ <tr>
+ <td>95</td>
+ <td>99.2</td>
+ <td>Rob</td>
+ <td>$16.24</td>
+
+ <td>2010-08-07</td>
+ </tr>
+ <tr>
+ <td>96</td>
+ <td>911.8</td>
+ <td>Walt</td>
+ <td>$72.44</td>
+
+ <td>2010-01-31</td>
+ </tr>
+ <tr>
+ <td>97</td>
+ <td>623</td>
+ <td>Nathan</td>
+ <td>$19.24</td>
+
+ <td>2008-10-03</td>
+ </tr>
+ <tr>
+ <td>98</td>
+ <td>673.4</td>
+ <td>Dan</td>
+ <td>$5.03</td>
+
+ <td>2010-09-29</td>
+ </tr>
+ <tr>
+ <td>99</td>
+ <td>402.8</td>
+ <td>Jeff</td>
+ <td>$73.84</td>
+
+ <td>2008-01-06</td>
+ </tr>
+ <tr>
+ <td>100</td>
+ <td>584.8</td>
+ <td>Bill</td>
+ <td>$73.24</td>
+
+ <td>2010-07-26</td>
+ </tr>
+ <tr>
+ <td>101</td>
+ <td>721.7</td>
+ <td>Joe</td>
+ <td>$10.64</td>
+
+ <td>2009-08-06</td>
+ </tr>
+ <tr>
+ <td>102</td>
+ <td>938.1</td>
+ <td>Bob</td>
+ <td>$15.64</td>
+
+ <td>2011-02-11</td>
+ </tr>
+ <tr>
+ <td>103</td>
+ <td>447.1</td>
+ <td>Matt</td>
+ <td>$37.94</td>
+
+ <td>2008-12-12</td>
+ </tr>
+ <tr>
+ <td>104</td>
+ <td>915.9</td>
+ <td>Mark</td>
+ <td>$64.34</td>
+
+ <td>2009-07-05</td>
+ </tr>
+ <tr>
+ <td>105</td>
+ <td>124.2</td>
+ <td>Tom</td>
+ <td>$74.24</td>
+
+ <td>2010-01-08</td>
+ </tr>
+ <tr>
+ <td>106</td>
+ <td>955.3</td>
+ <td>Jake</td>
+ <td>$65.34</td>
+
+ <td>2009-02-23</td>
+ </tr>
+ <tr>
+ <td>107</td>
+ <td>623.6</td>
+ <td>Greg</td>
+ <td>$27.64</td>
+
+ <td>2009-10-02</td>
+ </tr>
+ <tr>
+ <td>108</td>
+ <td>872.6</td>
+ <td>Adam</td>
+ <td>$95.04</td>
+
+ <td>2009-11-30</td>
+ </tr>
+ <tr>
+ <td>109</td>
+ <td>749.4</td>
+ <td>Steve</td>
+ <td>$35.34</td>
+
+ <td>2009-01-30</td>
+ </tr>
+ <tr>
+ <td>110</td>
+ <td>764.7</td>
+ <td>George</td>
+ <td>$93.74</td>
+
+ <td>2008-03-26</td>
+ </tr>
+ <tr>
+ <td>111</td>
+ <td>585.4</td>
+ <td>John</td>
+ <td>$65.94</td>
+
+ <td>2008-07-26</td>
+ </tr>
+ <tr>
+ <td>112</td>
+ <td>99.8</td>
+ <td>Phil</td>
+ <td>$59.74</td>
+
+ <td>2009-01-23</td>
+ </tr>
+ <tr>
+ <td>113</td>
+ <td>93.2</td>
+ <td>Jack</td>
+ <td>$4.43</td>
+
+ <td>2010-04-06</td>
+ </tr>
+ <tr>
+ <td>114</td>
+ <td>403.3</td>
+ <td>Paul</td>
+ <td>$96.04</td>
+
+ <td>2009-02-16</td>
+ </tr>
+ <tr>
+ <td>115</td>
+ <td>890.2</td>
+ <td>Rob</td>
+ <td>$8.43</td>
+
+ <td>2008-04-23</td>
+ </tr>
+ <tr>
+ <td>116</td>
+ <td>538.9</td>
+ <td>Walt</td>
+ <td>$3.93</td>
+
+ <td>2010-05-19</td>
+ </tr>
+ <tr>
+ <td>117</td>
+ <td>911.6</td>
+ <td>Nathan</td>
+ <td>$66.34</td>
+
+ <td>2008-02-02</td>
+ </tr>
+ <tr>
+ <td>118</td>
+ <td>475.9</td>
+ <td>Dan</td>
+ <td>$53.54</td>
+
+ <td>2011-02-05</td>
+ </tr>
+ <tr>
+ <td>119</td>
+ <td>90.7</td>
+ <td>Jeff</td>
+ <td>$28.54</td>
+
+ <td>2009-01-16</td>
+ </tr>
+ <tr>
+ <td>120</td>
+ <td>443.3</td>
+ <td>Bill</td>
+ <td>$5.03</td>
+
+ <td>2008-11-05</td>
+ </tr>
+ <tr>
+ <td>121</td>
+ <td>527.7</td>
+ <td>Joe</td>
+ <td>$63.54</td>
+
+ <td>2010-12-07</td>
+ </tr>
+ <tr>
+ <td>122</td>
+ <td>717.7</td>
+ <td>Bob</td>
+ <td>$73.54</td>
+
+ <td>2009-08-28</td>
+ </tr>
+ <tr>
+ <td>123</td>
+ <td>63.5</td>
+ <td>Matt</td>
+ <td>$82.84</td>
+
+ <td>2009-10-18</td>
+ </tr>
+ <tr>
+ <td>124</td>
+ <td>788</td>
+ <td>Mark</td>
+ <td>$23.14</td>
+
+ <td>2009-09-02</td>
+ </tr>
+ <tr>
+ <td>125</td>
+ <td>155</td>
+ <td>Tom</td>
+ <td>$12.14</td>
+
+ <td>2009-12-08</td>
+ </tr>
+ <tr>
+ <td>126</td>
+ <td>263.6</td>
+ <td>Jake</td>
+ <td>$66.04</td>
+
+ <td>2010-01-22</td>
+ </tr>
+ <tr>
+ <td>127</td>
+ <td>25.6</td>
+ <td>Greg</td>
+ <td>$57.24</td>
+
+ <td>2008-12-28</td>
+ </tr>
+ <tr>
+ <td>128</td>
+ <td>63.9</td>
+ <td>Adam</td>
+ <td>$4.73</td>
+
+ <td>2010-09-09</td>
+ </tr>
+ <tr>
+ <td>129</td>
+ <td>52</td>
+ <td>Steve</td>
+ <td>$13.84</td>
+
+ <td>2008-06-03</td>
+ </tr>
+ <tr>
+ <td>130</td>
+ <td>392.5</td>
+ <td>George</td>
+ <td>$58.14</td>
+
+ <td>2008-07-31</td>
+ </tr>
+ <tr>
+ <td>131</td>
+ <td>670.3</td>
+ <td>John</td>
+ <td>$10.94</td>
+
+ <td>2010-08-04</td>
+ </tr>
+ <tr>
+ <td>132</td>
+ <td>607</td>
+ <td>Phil</td>
+ <td>$82.74</td>
+
+ <td>2009-10-01</td>
+ </tr>
+ <tr>
+ <td>133</td>
+ <td>140.7</td>
+ <td>Jack</td>
+ <td>$89.04</td>
+
+ <td>2009-03-16</td>
+ </tr>
+ <tr>
+ <td>134</td>
+ <td>718.3</td>
+ <td>Paul</td>
+ <td>$67.84</td>
+
+ <td>2009-12-08</td>
+ </tr>
+ <tr>
+ <td>135</td>
+ <td>255.9</td>
+ <td>Rob</td>
+ <td>$83.34</td>
+
+ <td>2010-04-27</td>
+ </tr>
+ <tr>
+ <td>136</td>
+ <td>877.6</td>
+ <td>Walt</td>
+ <td>$9.73</td>
+
+ <td>2009-03-29</td>
+ </tr>
+ <tr>
+ <td>137</td>
+ <td>538.6</td>
+ <td>Nathan</td>
+ <td>$12.24</td>
+
+ <td>2011-01-20</td>
+ </tr>
+ <tr>
+ <td>138</td>
+ <td>862.5</td>
+ <td>Dan</td>
+ <td>$18.64</td>
+
+ <td>2008-01-13</td>
+ </tr>
+ <tr>
+ <td>139</td>
+ <td>721.9</td>
+ <td>Jeff</td>
+ <td>$23.84</td>
+
+ <td>2008-06-21</td>
+ </tr>
+ <tr>
+ <td>140</td>
+ <td>866.2</td>
+ <td>Bill</td>
+ <td>$63.04</td>
+
+ <td>2010-04-25</td>
+ </tr>
+ <tr>
+ <td>141</td>
+ <td>59.9</td>
+ <td>Joe</td>
+ <td>$30.14</td>
+
+ <td>2010-08-29</td>
+ </tr>
+ <tr>
+ <td>142</td>
+ <td>888.4</td>
+ <td>Bob</td>
+ <td>$90.84</td>
+
+ <td>2010-02-09</td>
+ </tr>
+ <tr>
+ <td>143</td>
+ <td>451.5</td>
+ <td>Matt</td>
+ <td>$4.83</td>
+
+ <td>2009-10-05</td>
+ </tr>
+ <tr>
+ <td>144</td>
+ <td>842.2</td>
+ <td>Mark</td>
+ <td>$76.74</td>
+
+ <td>2008-09-27</td>
+ </tr>
+ <tr>
+ <td>145</td>
+ <td>463.9</td>
+ <td>Tom</td>
+ <td>$2.23</td>
+
+ <td>2008-03-18</td>
+ </tr>
+ <tr>
+ <td>146</td>
+ <td>206.6</td>
+ <td>Jake</td>
+ <td>$90.04</td>
+
+ <td>2008-07-08</td>
+ </tr>
+ <tr>
+ <td>147</td>
+ <td>609.3</td>
+ <td>Greg</td>
+ <td>$43.84</td>
+
+ <td>2008-11-26</td>
+ </tr>
+ <tr>
+ <td>148</td>
+ <td>583.6</td>
+ <td>Adam</td>
+ <td>$30.14</td>
+
+ <td>2009-06-29</td>
+ </tr>
+ <tr>
+ <td>149</td>
+ <td>605.2</td>
+ <td>Steve</td>
+ <td>$2.33</td>
+
+ <td>2010-03-31</td>
+ </tr>
+ <tr>
+ <td>150</td>
+ <td>764.8</td>
+ <td>George</td>
+ <td>$88.94</td>
+
+ <td>2009-01-27</td>
+ </tr>
+ <tr>
+ <td>151</td>
+ <td>505.6</td>
+ <td>John</td>
+ <td>$94.94</td>
+
+ <td>2010-01-10</td>
+ </tr>
+ <tr>
+ <td>152</td>
+ <td>355.4</td>
+ <td>Phil</td>
+ <td>$83.74</td>
+
+ <td>2009-09-25</td>
+ </tr>
+ <tr>
+ <td>153</td>
+ <td>31.9</td>
+ <td>Jack</td>
+ <td>$28.84</td>
+
+ <td>2009-11-20</td>
+ </tr>
+ <tr>
+ <td>154</td>
+ <td>598.4</td>
+ <td>Paul</td>
+ <td>$13.14</td>
+
+ <td>2009-02-23</td>
+ </tr>
+ <tr>
+ <td>155</td>
+ <td>842.9</td>
+ <td>Rob</td>
+ <td>$59.44</td>
+
+ <td>2009-03-20</td>
+ </tr>
+ <tr>
+ <td>156</td>
+ <td>920.5</td>
+ <td>Walt</td>
+ <td>$80.14</td>
+
+ <td>2008-11-24</td>
+ </tr>
+ <tr>
+ <td>157</td>
+ <td>94.5</td>
+ <td>Nathan</td>
+ <td>$41.04</td>
+
+ <td>2010-04-16</td>
+ </tr>
+ <tr>
+ <td>158</td>
+ <td>390.6</td>
+ <td>Dan</td>
+ <td>$99.44</td>
+
+ <td>2008-01-28</td>
+ </tr>
+ <tr>
+ <td>159</td>
+ <td>872.6</td>
+ <td>Jeff</td>
+ <td>$59.94</td>
+
+ <td>2008-02-23</td>
+ </tr>
+ <tr>
+ <td>160</td>
+ <td>592.3</td>
+ <td>Bill</td>
+ <td>$36.44</td>
+
+ <td>2010-12-18</td>
+ </tr>
+ <tr>
+ <td>161</td>
+ <td>942.4</td>
+ <td>Joe</td>
+ <td>$86.94</td>
+
+ <td>2010-10-19</td>
+ </tr>
+ <tr>
+ <td>162</td>
+ <td>593</td>
+ <td>Bob</td>
+ <td>$22.44</td>
+
+ <td>2010-04-13</td>
+ </tr>
+ <tr>
+ <td>163</td>
+ <td>151.1</td>
+ <td>Matt</td>
+ <td>$25.64</td>
+
+ <td>2008-01-11</td>
+ </tr>
+ <tr>
+ <td>164</td>
+ <td>757.4</td>
+ <td>Mark</td>
+ <td>$85.54</td>
+
+ <td>2008-06-10</td>
+ </tr>
+ <tr>
+ <td>165</td>
+ <td>130</td>
+ <td>Tom</td>
+ <td>$69.84</td>
+
+ <td>2010-04-29</td>
+ </tr>
+ <tr>
+ <td>166</td>
+ <td>525</td>
+ <td>Jake</td>
+ <td>$61.84</td>
+
+ <td>2009-09-10</td>
+ </tr>
+ <tr>
+ <td>167</td>
+ <td>819.8</td>
+ <td>Greg</td>
+ <td>$71.34</td>
+
+ <td>2010-12-29</td>
+ </tr>
+ <tr>
+ <td>168</td>
+ <td>552.9</td>
+ <td>Adam</td>
+ <td>$10.34</td>
+
+ <td>2010-12-22</td>
+ </tr>
+ <tr>
+ <td>169</td>
+ <td>586.8</td>
+ <td>Steve</td>
+ <td>$97.54</td>
+
+ <td>2009-09-13</td>
+ </tr>
+ <tr>
+ <td>170</td>
+ <td>643.5</td>
+ <td>George</td>
+ <td>$56.84</td>
+
+ <td>2010-11-08</td>
+ </tr>
+ <tr>
+ <td>171</td>
+ <td>588.9</td>
+ <td>John</td>
+ <td>$51.04</td>
+
+ <td>2010-06-10</td>
+ </tr>
+ <tr>
+ <td>172</td>
+ <td>482.9</td>
+ <td>Phil</td>
+ <td>$10.34</td>
+
+ <td>2007-12-25</td>
+ </tr>
+ <tr>
+ <td>173</td>
+ <td>213.9</td>
+ <td>Jack</td>
+ <td>$25.44</td>
+
+ <td>2008-10-17</td>
+ </tr>
+ <tr>
+ <td>174</td>
+ <td>233.2</td>
+ <td>Paul</td>
+ <td>$1.13</td>
+
+ <td>2008-05-01</td>
+ </tr>
+ <tr>
+ <td>175</td>
+ <td>383</td>
+ <td>Rob</td>
+ <td>$14.24</td>
+
+ <td>2010-07-18</td>
+ </tr>
+ <tr>
+ <td>176</td>
+ <td>127.1</td>
+ <td>Walt</td>
+ <td>$66.74</td>
+
+ <td>2009-05-01</td>
+ </tr>
+ <tr>
+ <td>177</td>
+ <td>672.2</td>
+ <td>Nathan</td>
+ <td>$48.64</td>
+
+ <td>2008-06-03</td>
+ </tr>
+ <tr>
+ <td>178</td>
+ <td>627.4</td>
+ <td>Dan</td>
+ <td>$3.93</td>
+
+ <td>2008-09-30</td>
+ </tr>
+ <tr>
+ <td>179</td>
+ <td>576.3</td>
+ <td>Jeff</td>
+ <td>$62.64</td>
+
+ <td>2008-09-01</td>
+ </tr>
+ <tr>
+ <td>180</td>
+ <td>124.1</td>
+ <td>Bill</td>
+ <td>$26.94</td>
+
+ <td>2010-06-20</td>
+ </tr>
+ <tr>
+ <td>181</td>
+ <td>35.3</td>
+ <td>Joe</td>
+ <td>$85.84</td>
+
+ <td>2008-11-30</td>
+ </tr>
+ <tr>
+ <td>182</td>
+ <td>815.7</td>
+ <td>Bob</td>
+ <td>$34.14</td>
+
+ <td>2009-03-30</td>
+ </tr>
+ <tr>
+ <td>183</td>
+ <td>820.6</td>
+ <td>Matt</td>
+ <td>$55.54</td>
+
+ <td>2010-01-18</td>
+ </tr>
+ <tr>
+ <td>184</td>
+ <td>81.8</td>
+ <td>Mark</td>
+ <td>$78.84</td>
+
+ <td>2010-01-31</td>
+ </tr>
+ <tr>
+ <td>185</td>
+ <td>197.5</td>
+ <td>Tom</td>
+ <td>$17.14</td>
+
+ <td>2010-07-14</td>
+ </tr>
+ <tr>
+ <td>186</td>
+ <td>10.8</td>
+ <td>Jake</td>
+ <td>$29.84</td>
+
+ <td>2009-06-23</td>
+ </tr>
+ <tr>
+ <td>187</td>
+ <td>442</td>
+ <td>Greg</td>
+ <td>$97.04</td>
+
+ <td>2011-01-06</td>
+ </tr>
+ <tr>
+ <td>188</td>
+ <td>585.7</td>
+ <td>Adam</td>
+ <td>$59.74</td>
+
+ <td>2007-12-21</td>
+ </tr>
+ <tr>
+ <td>189</td>
+ <td>832.2</td>
+ <td>Steve</td>
+ <td>$17.44</td>
+
+ <td>2009-12-14</td>
+ </tr>
+ <tr>
+ <td>190</td>
+ <td>54.3</td>
+ <td>George</td>
+ <td>$29.84</td>
+
+ <td>2010-10-22</td>
+ </tr>
+ <tr>
+ <td>191</td>
+ <td>844</td>
+ <td>John</td>
+ <td>$33.34</td>
+
+ <td>2010-05-10</td>
+ </tr>
+ <tr>
+ <td>192</td>
+ <td>143.9</td>
+ <td>Phil</td>
+ <td>$14.94</td>
+
+ <td>2008-04-07</td>
+ </tr>
+ <tr>
+ <td>193</td>
+ <td>546.8</td>
+ <td>Jack</td>
+ <td>$96.94</td>
+
+ <td>2010-01-09</td>
+ </tr>
+ <tr>
+ <td>194</td>
+ <td>203.8</td>
+ <td>Paul</td>
+ <td>$5.13</td>
+
+ <td>2009-05-09</td>
+ </tr>
+ <tr>
+ <td>195</td>
+ <td>872.3</td>
+ <td>Rob</td>
+ <td>$24.84</td>
+
+ <td>2009-11-22</td>
+ </tr>
+ <tr>
+ <td>196</td>
+ <td>682.3</td>
+ <td>Walt</td>
+ <td>$25.94</td>
+
+ <td>2010-11-02</td>
+ </tr>
+ <tr>
+ <td>197</td>
+ <td>158.7</td>
+ <td>Nathan</td>
+ <td>$70.14</td>
+
+ <td>2010-09-28</td>
+ </tr>
+ <tr>
+ <td>198</td>
+ <td>121.2</td>
+ <td>Dan</td>
+ <td>$28.74</td>
+
+ <td>2009-06-19</td>
+ </tr>
+ <tr>
+ <td>199</td>
+ <td>122.6</td>
+ <td>Jeff</td>
+ <td>$11.94</td>
+
+ <td>2010-01-06</td>
+ </tr>
+ <tr>
+ <td>200</td>
+ <td>749.8</td>
+ <td>Bill</td>
+ <td>$17.34</td>
+
+ <td>2010-12-17</td>
+ </tr>
+ <tr>
+ <td>201</td>
+ <td>646.1</td>
+ <td>Joe</td>
+ <td>$1.73</td>
+
+ <td>2008-11-05</td>
+ </tr>
+ <tr>
+ <td>202</td>
+ <td>400.4</td>
+ <td>Bob</td>
+ <td>$16.14</td>
+
+ <td>2009-04-26</td>
+ </tr>
+ <tr>
+ <td>203</td>
+ <td>495.5</td>
+ <td>Matt</td>
+ <td>$70.84</td>
+
+ <td>2009-03-21</td>
+ </tr>
+ <tr>
+ <td>204</td>
+ <td>145.3</td>
+ <td>Mark</td>
+ <td>$91.24</td>
+
+ <td>2009-05-19</td>
+ </tr>
+ <tr>
+ <td>205</td>
+ <td>582.9</td>
+ <td>Tom</td>
+ <td>$78.44</td>
+
+ <td>2010-03-02</td>
+ </tr>
+ <tr>
+ <td>206</td>
+ <td>191.3</td>
+ <td>Jake</td>
+ <td>$46.64</td>
+
+ <td>2010-12-27</td>
+ </tr>
+ <tr>
+ <td>207</td>
+ <td>97.5</td>
+ <td>Greg</td>
+ <td>$62.54</td>
+
+ <td>2010-01-15</td>
+ </tr>
+ <tr>
+ <td>208</td>
+ <td>973.7</td>
+ <td>Adam</td>
+ <td>$74.64</td>
+
+ <td>2010-12-13</td>
+ </tr>
+ <tr>
+ <td>209</td>
+ <td>447.2</td>
+ <td>Steve</td>
+ <td>$86.84</td>
+
+ <td>2008-02-27</td>
+ </tr>
+ <tr>
+ <td>210</td>
+ <td>94.3</td>
+ <td>George</td>
+ <td>$61.84</td>
+
+ <td>2008-09-15</td>
+ </tr>
+ <tr>
+ <td>211</td>
+ <td>39</td>
+ <td>John</td>
+ <td>$26.44</td>
+
+ <td>2008-10-04</td>
+ </tr>
+ <tr>
+ <td>212</td>
+ <td>316.7</td>
+ <td>Phil</td>
+ <td>$66.54</td>
+
+ <td>2009-04-09</td>
+ </tr>
+ <tr>
+ <td>213</td>
+ <td>743</td>
+ <td>Jack</td>
+ <td>$16.04</td>
+
+ <td>2008-05-05</td>
+ </tr>
+ <tr>
+ <td>214</td>
+ <td>138.4</td>
+ <td>Paul</td>
+ <td>$30.54</td>
+
+ <td>2008-01-24</td>
+ </tr>
+ <tr>
+ <td>215</td>
+ <td>584.7</td>
+ <td>Rob</td>
+ <td>$88.84</td>
+
+ <td>2010-07-19</td>
+ </tr>
+ <tr>
+ <td>216</td>
+ <td>279.3</td>
+ <td>Walt</td>
+ <td>$7.93</td>
+
+ <td>2008-11-08</td>
+ </tr>
+ <tr>
+ <td>217</td>
+ <td>233</td>
+ <td>Nathan</td>
+ <td>$17.74</td>
+
+ <td>2010-11-01</td>
+ </tr>
+ <tr>
+ <td>218</td>
+ <td>887.8</td>
+ <td>Dan</td>
+ <td>$15.04</td>
+
+ <td>2010-01-11</td>
+ </tr>
+ <tr>
+ <td>219</td>
+ <td>829.3</td>
+ <td>Jeff</td>
+ <td>$59.84</td>
+
+ <td>2009-08-12</td>
+ </tr>
+ <tr>
+ <td>220</td>
+ <td>889.7</td>
+ <td>Bill</td>
+ <td>$69.24</td>
+
+ <td>2008-05-27</td>
+ </tr>
+ <tr>
+ <td>221</td>
+ <td>123.3</td>
+ <td>Joe</td>
+ <td>$73.14</td>
+
+ <td>2009-03-29</td>
+ </tr>
+ <tr>
+ <td>222</td>
+ <td>373.9</td>
+ <td>Bob</td>
+ <td>$4.73</td>
+
+ <td>2008-03-06</td>
+ </tr>
+ <tr>
+ <td>223</td>
+ <td>785.6</td>
+ <td>Matt</td>
+ <td>$79.04</td>
+
+ <td>2008-09-07</td>
+ </tr>
+ <tr>
+ <td>224</td>
+ <td>904.9</td>
+ <td>Mark</td>
+ <td>$92.94</td>
+
+ <td>2009-08-26</td>
+ </tr>
+ <tr>
+ <td>225</td>
+ <td>935.8</td>
+ <td>Tom</td>
+ <td>$51.34</td>
+
+ <td>2009-04-19</td>
+ </tr>
+ <tr>
+ <td>226</td>
+ <td>750.5</td>
+ <td>Jake</td>
+ <td>$79.34</td>
+
+ <td>2009-07-19</td>
+ </tr>
+ <tr>
+ <td>227</td>
+ <td>31.2</td>
+ <td>Greg</td>
+ <td>$2.53</td>
+
+ <td>2010-02-09</td>
+ </tr>
+ <tr>
+ <td>228</td>
+ <td>936.7</td>
+ <td>Adam</td>
+ <td>$91.34</td>
+
+ <td>2010-08-02</td>
+ </tr>
+ <tr>
+ <td>229</td>
+ <td>588</td>
+ <td>Steve</td>
+ <td>$74.24</td>
+
+ <td>2009-04-23</td>
+ </tr>
+ <tr>
+ <td>230</td>
+ <td>107.7</td>
+ <td>George</td>
+ <td>$63.24</td>
+
+ <td>2008-05-01</td>
+ </tr>
+ <tr>
+ <td>231</td>
+ <td>245.7</td>
+ <td>John</td>
+ <td>$75.54</td>
+
+ <td>2010-08-25</td>
+ </tr>
+ <tr>
+ <td>232</td>
+ <td>647.8</td>
+ <td>Phil</td>
+ <td>$12.94</td>
+
+ <td>2010-10-19</td>
+ </tr>
+ <tr>
+ <td>233</td>
+ <td>714.6</td>
+ <td>Jack</td>
+ <td>$91.54</td>
+
+ <td>2010-02-18</td>
+ </tr>
+ <tr>
+ <td>234</td>
+ <td>941.3</td>
+ <td>Paul</td>
+ <td>$82.04</td>
+
+ <td>2009-11-28</td>
+ </tr>
+ <tr>
+ <td>235</td>
+ <td>473.3</td>
+ <td>Rob</td>
+ <td>$75.54</td>
+
+ <td>2008-05-13</td>
+ </tr>
+ <tr>
+ <td>236</td>
+ <td>893.4</td>
+ <td>Walt</td>
+ <td>$50.64</td>
+
+ <td>2010-11-17</td>
+ </tr>
+ <tr>
+ <td>237</td>
+ <td>392.7</td>
+ <td>Nathan</td>
+ <td>$53.74</td>
+
+ <td>2010-12-16</td>
+ </tr>
+ <tr>
+ <td>238</td>
+ <td>68.8</td>
+ <td>Dan</td>
+ <td>$47.44</td>
+
+ <td>2010-09-06</td>
+ </tr>
+ <tr>
+ <td>239</td>
+ <td>895.2</td>
+ <td>Jeff</td>
+ <td>$6.13</td>
+
+ <td>2009-11-12</td>
+ </tr>
+ <tr>
+ <td>240</td>
+ <td>319.1</td>
+ <td>Bill</td>
+ <td>$16.94</td>
+
+ <td>2008-09-12</td>
+ </tr>
+ <tr>
+ <td>241</td>
+ <td>434.7</td>
+ <td>Joe</td>
+ <td>$41.54</td>
+
+ <td>2011-02-04</td>
+ </tr>
+ <tr>
+ <td>242</td>
+ <td>281.1</td>
+ <td>Bob</td>
+ <td>$6.33</td>
+
+ <td>2008-05-02</td>
+ </tr>
+ <tr>
+ <td>243</td>
+ <td>174.8</td>
+ <td>Matt</td>
+ <td>$77.74</td>
+
+ <td>2008-01-24</td>
+ </tr>
+ <tr>
+ <td>244</td>
+ <td>859</td>
+ <td>Mark</td>
+ <td>$71.84</td>
+
+ <td>2010-08-30</td>
+ </tr>
+ <tr>
+ <td>245</td>
+ <td>471.8</td>
+ <td>Tom</td>
+ <td>$19.14</td>
+
+ <td>2009-11-19</td>
+ </tr>
+ <tr>
+ <td>246</td>
+ <td>597.9</td>
+ <td>Jake</td>
+ <td>$8.53</td>
+
+ <td>2008-04-26</td>
+ </tr>
+ <tr>
+ <td>247</td>
+ <td>516.5</td>
+ <td>Greg</td>
+ <td>$47.84</td>
+
+ <td>2010-01-08</td>
+ </tr>
+ <tr>
+ <td>248</td>
+ <td>460.6</td>
+ <td>Adam</td>
+ <td>$54.64</td>
+
+ <td>2008-05-08</td>
+ </tr>
+ <tr>
+ <td>249</td>
+ <td>317.8</td>
+ <td>Steve</td>
+ <td>$44.14</td>
+
+ <td>2008-07-18</td>
+ </tr>
+ <tr>
+ <td>250</td>
+ <td>917.4</td>
+ <td>George</td>
+ <td>$76.04</td>
+
+ <td>2009-01-30</td>
+ </tr>
+ <tr>
+ <td>251</td>
+ <td>149.1</td>
+ <td>John</td>
+ <td>$19.54</td>
+
+ <td>2010-05-25</td>
+ </tr>
+ <tr>
+ <td>252</td>
+ <td>136.1</td>
+ <td>Phil</td>
+ <td>$47.64</td>
+
+ <td>2010-08-05</td>
+ </tr>
+ <tr>
+ <td>253</td>
+ <td>252.2</td>
+ <td>Jack</td>
+ <td>$65.14</td>
+
+ <td>2009-11-20</td>
+ </tr>
+ <tr>
+ <td>254</td>
+ <td>283</td>
+ <td>Paul</td>
+ <td>$51.04</td>
+
+ <td>2008-12-29</td>
+ </tr>
+ <tr>
+ <td>255</td>
+ <td>133.3</td>
+ <td>Rob</td>
+ <td>$98.24</td>
+
+ <td>2009-08-08</td>
+ </tr>
+ <tr>
+ <td>256</td>
+ <td>739</td>
+ <td>Walt</td>
+ <td>$57.94</td>
+
+ <td>2009-11-14</td>
+ </tr>
+ <tr>
+ <td>257</td>
+ <td>850.4</td>
+ <td>Nathan</td>
+ <td>$9.63</td>
+
+ <td>2008-03-19</td>
+ </tr>
+ <tr>
+ <td>258</td>
+ <td>498.6</td>
+ <td>Dan</td>
+ <td>$55.64</td>
+
+ <td>2009-12-11</td>
+ </tr>
+ <tr>
+ <td>259</td>
+ <td>620.3</td>
+ <td>Jeff</td>
+ <td>$87.44</td>
+
+ <td>2008-03-04</td>
+ </tr>
+ <tr>
+ <td>260</td>
+ <td>803.4</td>
+ <td>Bill</td>
+ <td>$79.14</td>
+
+ <td>2010-08-01</td>
+ </tr>
+ <tr>
+ <td>261</td>
+ <td>155.5</td>
+ <td>Joe</td>
+ <td>$94.04</td>
+
+ <td>2008-01-13</td>
+ </tr>
+ <tr>
+ <td>262</td>
+ <td>922.3</td>
+ <td>Bob</td>
+ <td>$7.63</td>
+
+ <td>2009-07-17</td>
+ </tr>
+ <tr>
+ <td>263</td>
+ <td>751.6</td>
+ <td>Matt</td>
+ <td>$32.94</td>
+
+ <td>2008-06-07</td>
+ </tr>
+ <tr>
+ <td>264</td>
+ <td>357.9</td>
+ <td>Mark</td>
+ <td>$61.14</td>
+
+ <td>2010-01-18</td>
+ </tr>
+ <tr>
+ <td>265</td>
+ <td>682.4</td>
+ <td>Tom</td>
+ <td>$74.54</td>
+
+ <td>2009-12-28</td>
+ </tr>
+ <tr>
+ <td>266</td>
+ <td>198.4</td>
+ <td>Jake</td>
+ <td>$48.44</td>
+
+ <td>2008-08-28</td>
+ </tr>
+ <tr>
+ <td>267</td>
+ <td>799.1</td>
+ <td>Greg</td>
+ <td>$33.44</td>
+
+ <td>2008-12-17</td>
+ </tr>
+ <tr>
+ <td>268</td>
+ <td>877.4</td>
+ <td>Adam</td>
+ <td>$83.34</td>
+
+ <td>2010-09-21</td>
+ </tr>
+ <tr>
+ <td>269</td>
+ <td>501.7</td>
+ <td>Steve</td>
+ <td>$45.34</td>
+
+ <td>2010-04-28</td>
+ </tr>
+ <tr>
+ <td>270</td>
+ <td>567.4</td>
+ <td>George</td>
+ <td>$25.64</td>
+
+ <td>2009-08-30</td>
+ </tr>
+ <tr>
+ <td>271</td>
+ <td>393.4</td>
+ <td>John</td>
+ <td>$41.14</td>
+
+ <td>2009-06-22</td>
+ </tr>
+ <tr>
+ <td>272</td>
+ <td>414.4</td>
+ <td>Phil</td>
+ <td>$33.44</td>
+
+ <td>2009-09-18</td>
+ </tr>
+ <tr>
+ <td>273</td>
+ <td>911.4</td>
+ <td>Jack</td>
+ <td>$8.53</td>
+
+ <td>2010-10-03</td>
+ </tr>
+ <tr>
+ <td>274</td>
+ <td>59.2</td>
+ <td>Paul</td>
+ <td>$44.34</td>
+
+ <td>2009-07-10</td>
+ </tr>
+ <tr>
+ <td>275</td>
+ <td>716.7</td>
+ <td>Rob</td>
+ <td>$12.64</td>
+
+ <td>2008-09-18</td>
+ </tr>
+ <tr>
+ <td>276</td>
+ <td>355.7</td>
+ <td>Walt</td>
+ <td>$32.44</td>
+
+ <td>2010-04-01</td>
+ </tr>
+ <tr>
+ <td>277</td>
+ <td>573.9</td>
+ <td>Nathan</td>
+ <td>$12.34</td>
+
+ <td>2008-02-20</td>
+ </tr>
+ <tr>
+ <td>278</td>
+ <td>887.7</td>
+ <td>Dan</td>
+ <td>$0.03</td>
+
+ <td>2010-10-10</td>
+ </tr>
+ <tr>
+ <td>279</td>
+ <td>757.8</td>
+ <td>Jeff</td>
+ <td>$50.24</td>
+
+ <td>2009-01-15</td>
+ </tr>
+ <tr>
+ <td>280</td>
+ <td>501.7</td>
+ <td>Bill</td>
+ <td>$6.93</td>
+
+ <td>2009-11-07</td>
+ </tr>
+ <tr>
+ <td>281</td>
+ <td>36.9</td>
+ <td>Joe</td>
+ <td>$46.34</td>
+
+ <td>2007-12-27</td>
+ </tr>
+ <tr>
+ <td>282</td>
+ <td>512.4</td>
+ <td>Bob</td>
+ <td>$87.74</td>
+
+ <td>2009-01-16</td>
+ </tr>
+ <tr>
+ <td>283</td>
+ <td>64.3</td>
+ <td>Matt</td>
+ <td>$78.84</td>
+
+ <td>2009-04-25</td>
+ </tr>
+ <tr>
+ <td>284</td>
+ <td>944.6</td>
+ <td>Mark</td>
+ <td>$84.74</td>
+
+ <td>2010-09-20</td>
+ </tr>
+ <tr>
+ <td>285</td>
+ <td>436.3</td>
+ <td>Tom</td>
+ <td>$56.44</td>
+
+ <td>2011-02-12</td>
+ </tr>
+ <tr>
+ <td>286</td>
+ <td>672.6</td>
+ <td>Jake</td>
+ <td>$92.04</td>
+
+ <td>2008-12-21</td>
+ </tr>
+ <tr>
+ <td>287</td>
+ <td>392.6</td>
+ <td>Greg</td>
+ <td>$49.44</td>
+
+ <td>2009-05-13</td>
+ </tr>
+ <tr>
+ <td>288</td>
+ <td>446.5</td>
+ <td>Adam</td>
+ <td>$38.14</td>
+
+ <td>2009-05-13</td>
+ </tr>
+ <tr>
+ <td>289</td>
+ <td>333</td>
+ <td>Steve</td>
+ <td>$13.94</td>
+
+ <td>2010-12-15</td>
+ </tr>
+ <tr>
+ <td>290</td>
+ <td>672.1</td>
+ <td>George</td>
+ <td>$64.14</td>
+
+ <td>2008-01-02</td>
+ </tr>
+ <tr>
+ <td>291</td>
+ <td>267.3</td>
+ <td>John</td>
+ <td>$67.84</td>
+
+ <td>2009-06-21</td>
+ </tr>
+ <tr>
+ <td>292</td>
+ <td>273.9</td>
+ <td>Phil</td>
+ <td>$19.04</td>
+
+ <td>2009-01-29</td>
+ </tr>
+ <tr>
+ <td>293</td>
+ <td>614.3</td>
+ <td>Jack</td>
+ <td>$25.44</td>
+
+ <td>2008-05-29</td>
+ </tr>
+ <tr>
+ <td>294</td>
+ <td>40</td>
+ <td>Paul</td>
+ <td>$19.94</td>
+
+ <td>2011-02-04</td>
+ </tr>
+ <tr>
+ <td>295</td>
+ <td>908.8</td>
+ <td>Rob</td>
+ <td>$63.54</td>
+
+ <td>2009-09-17</td>
+ </tr>
+ <tr>
+ <td>296</td>
+ <td>903.1</td>
+ <td>Walt</td>
+ <td>$30.84</td>
+
+ <td>2009-06-17</td>
+ </tr>
+ <tr>
+ <td>297</td>
+ <td>221.2</td>
+ <td>Nathan</td>
+ <td>$70.04</td>
+
+ <td>2011-01-09</td>
+ </tr>
+ <tr>
+ <td>298</td>
+ <td>662.1</td>
+ <td>Dan</td>
+ <td>$14.74</td>
+
+ <td>2009-01-23</td>
+ </tr>
+ <tr>
+ <td>299</td>
+ <td>103.2</td>
+ <td>Jeff</td>
+ <td>$47.94</td>
+
+ <td>2009-07-03</td>
+ </tr>
+ <tr>
+ <td>300</td>
+ <td>46.2</td>
+ <td>Bill</td>
+ <td>$15.24</td>
+
+ <td>2008-05-13</td>
+ </tr>
+ <tr>
+ <td>301</td>
+ <td>58.3</td>
+ <td>Joe</td>
+ <td>$41.94</td>
+
+ <td>2010-07-06</td>
+ </tr>
+ <tr>
+ <td>302</td>
+ <td>533</td>
+ <td>Bob</td>
+ <td>$69.34</td>
+
+ <td>2011-02-10</td>
+ </tr>
+ <tr>
+ <td>303</td>
+ <td>884.6</td>
+ <td>Matt</td>
+ <td>$30.74</td>
+
+ <td>2008-09-30</td>
+ </tr>
+ <tr>
+ <td>304</td>
+ <td>24.5</td>
+ <td>Mark</td>
+ <td>$34.74</td>
+
+ <td>2009-05-18</td>
+ </tr>
+ <tr>
+ <td>305</td>
+ <td>11.7</td>
+ <td>Tom</td>
+ <td>$25.64</td>
+
+ <td>2008-03-22</td>
+ </tr>
+ <tr>
+ <td>306</td>
+ <td>563</td>
+ <td>Jake</td>
+ <td>$15.94</td>
+
+ <td>2009-03-12</td>
+ </tr>
+ <tr>
+ <td>307</td>
+ <td>34.1</td>
+ <td>Greg</td>
+ <td>$38.04</td>
+
+ <td>2008-03-30</td>
+ </tr>
+ <tr>
+ <td>308</td>
+ <td>998.8</td>
+ <td>Adam</td>
+ <td>$4.23</td>
+
+ <td>2008-09-16</td>
+ </tr>
+ <tr>
+ <td>309</td>
+ <td>344.7</td>
+ <td>Steve</td>
+ <td>$14.54</td>
+
+ <td>2010-03-25</td>
+ </tr>
+ <tr>
+ <td>310</td>
+ <td>829.5</td>
+ <td>George</td>
+ <td>$19.14</td>
+
+ <td>2010-09-16</td>
+ </tr>
+ <tr>
+ <td>311</td>
+ <td>955</td>
+ <td>John</td>
+ <td>$24.94</td>
+
+ <td>2008-11-12</td>
+ </tr>
+ <tr>
+ <td>312</td>
+ <td>758</td>
+ <td>Phil</td>
+ <td>$78.34</td>
+
+ <td>2011-01-23</td>
+ </tr>
+ <tr>
+ <td>313</td>
+ <td>750.8</td>
+ <td>Jack</td>
+ <td>$66.74</td>
+
+ <td>2008-11-11</td>
+ </tr>
+ <tr>
+ <td>314</td>
+ <td>997.8</td>
+ <td>Paul</td>
+ <td>$69.14</td>
+
+ <td>2009-12-18</td>
+ </tr>
+ <tr>
+ <td>315</td>
+ <td>443.5</td>
+ <td>Rob</td>
+ <td>$70.34</td>
+
+ <td>2010-10-10</td>
+ </tr>
+ <tr>
+ <td>316</td>
+ <td>524</td>
+ <td>Walt</td>
+ <td>$26.64</td>
+
+ <td>2008-02-09</td>
+ </tr>
+ <tr>
+ <td>317</td>
+ <td>912</td>
+ <td>Nathan</td>
+ <td>$30.04</td>
+
+ <td>2009-04-24</td>
+ </tr>
+ <tr>
+ <td>318</td>
+ <td>1000</td>
+ <td>Dan</td>
+ <td>$29.94</td>
+
+ <td>2009-06-11</td>
+ </tr>
+ <tr>
+ <td>319</td>
+ <td>234.5</td>
+ <td>Jeff</td>
+ <td>$64.34</td>
+
+ <td>2009-11-26</td>
+ </tr>
+ <tr>
+ <td>320</td>
+ <td>948.4</td>
+ <td>Bill</td>
+ <td>$47.34</td>
+
+ <td>2010-07-05</td>
+ </tr>
+ <tr>
+ <td>321</td>
+ <td>813.7</td>
+ <td>Joe</td>
+ <td>$42.84</td>
+
+ <td>2008-02-18</td>
+ </tr>
+ <tr>
+ <td>322</td>
+ <td>97.7</td>
+ <td>Bob</td>
+ <td>$18.64</td>
+
+ <td>2010-08-11</td>
+ </tr>
+ <tr>
+ <td>323</td>
+ <td>74.3</td>
+ <td>Matt</td>
+ <td>$93.74</td>
+
+ <td>2009-07-22</td>
+ </tr>
+ <tr>
+ <td>324</td>
+ <td>357.7</td>
+ <td>Mark</td>
+ <td>$93.44</td>
+
+ <td>2008-07-29</td>
+ </tr>
+ <tr>
+ <td>325</td>
+ <td>988</td>
+ <td>Tom</td>
+ <td>$37.84</td>
+
+ <td>2010-10-21</td>
+ </tr>
+ <tr>
+ <td>326</td>
+ <td>873.8</td>
+ <td>Jake</td>
+ <td>$90.24</td>
+
+ <td>2008-06-24</td>
+ </tr>
+ <tr>
+ <td>327</td>
+ <td>918.3</td>
+ <td>Greg</td>
+ <td>$81.44</td>
+
+ <td>2009-06-06</td>
+ </tr>
+ <tr>
+ <td>328</td>
+ <td>342.7</td>
+ <td>Adam</td>
+ <td>$81.44</td>
+
+ <td>2010-05-18</td>
+ </tr>
+ <tr>
+ <td>329</td>
+ <td>809</td>
+ <td>Steve</td>
+ <td>$4.83</td>
+
+ <td>2009-03-31</td>
+ </tr>
+ <tr>
+ <td>330</td>
+ <td>420.4</td>
+ <td>George</td>
+ <td>$99.74</td>
+
+ <td>2010-09-30</td>
+ </tr>
+ <tr>
+ <td>331</td>
+ <td>223</td>
+ <td>John</td>
+ <td>$81.04</td>
+
+ <td>2008-12-06</td>
+ </tr>
+ <tr>
+ <td>332</td>
+ <td>275</td>
+ <td>Phil</td>
+ <td>$90.84</td>
+
+ <td>2009-07-09</td>
+ </tr>
+ <tr>
+ <td>333</td>
+ <td>109.5</td>
+ <td>Jack</td>
+ <td>$98.24</td>
+
+ <td>2009-04-27</td>
+ </tr>
+ <tr>
+ <td>334</td>
+ <td>610.9</td>
+ <td>Paul</td>
+ <td>$34.04</td>
+
+ <td>2009-02-10</td>
+ </tr>
+ <tr>
+ <td>335</td>
+ <td>803.7</td>
+ <td>Rob</td>
+ <td>$32.84</td>
+
+ <td>2010-04-23</td>
+ </tr>
+ <tr>
+ <td>336</td>
+ <td>699.6</td>
+ <td>Walt</td>
+ <td>$20.14</td>
+
+ <td>2009-12-30</td>
+ </tr>
+ <tr>
+ <td>337</td>
+ <td>861.4</td>
+ <td>Nathan</td>
+ <td>$12.04</td>
+
+ <td>2009-05-28</td>
+ </tr>
+ <tr>
+ <td>338</td>
+ <td>323.4</td>
+ <td>Dan</td>
+ <td>$46.24</td>
+
+ <td>2008-10-25</td>
+ </tr>
+ <tr>
+ <td>339</td>
+ <td>84.3</td>
+ <td>Jeff</td>
+ <td>$27.14</td>
+
+ <td>2008-12-19</td>
+ </tr>
+ <tr>
+ <td>340</td>
+ <td>488.6</td>
+ <td>Bill</td>
+ <td>$69.24</td>
+
+ <td>2008-12-15</td>
+ </tr>
+ <tr>
+ <td>341</td>
+ <td>365.7</td>
+ <td>Joe</td>
+ <td>$91.54</td>
+
+ <td>2008-05-10</td>
+ </tr>
+ <tr>
+ <td>342</td>
+ <td>670.8</td>
+ <td>Bob</td>
+ <td>$19.04</td>
+
+ <td>2008-01-24</td>
+ </tr>
+ <tr>
+ <td>343</td>
+ <td>161.5</td>
+ <td>Matt</td>
+ <td>$29.94</td>
+
+ <td>2008-01-03</td>
+ </tr>
+ <tr>
+ <td>344</td>
+ <td>588.8</td>
+ <td>Mark</td>
+ <td>$91.04</td>
+
+ <td>2009-01-30</td>
+ </tr>
+ <tr>
+ <td>345</td>
+ <td>950.3</td>
+ <td>Tom</td>
+ <td>$71.44</td>
+
+ <td>2010-02-13</td>
+ </tr>
+ <tr>
+ <td>346</td>
+ <td>689.5</td>
+ <td>Jake</td>
+ <td>$41.34</td>
+
+ <td>2010-10-04</td>
+ </tr>
+ <tr>
+ <td>347</td>
+ <td>330.4</td>
+ <td>Greg</td>
+ <td>$27.44</td>
+
+ <td>2007-12-20</td>
+ </tr>
+ <tr>
+ <td>348</td>
+ <td>785</td>
+ <td>Adam</td>
+ <td>$59.84</td>
+
+ <td>2009-06-07</td>
+ </tr>
+ <tr>
+ <td>349</td>
+ <td>53.2</td>
+ <td>Steve</td>
+ <td>$68.24</td>
+
+ <td>2010-04-17</td>
+ </tr>
+ <tr>
+ <td>350</td>
+ <td>369.6</td>
+ <td>George</td>
+ <td>$17.14</td>
+
+ <td>2009-04-25</td>
+ </tr>
+ <tr>
+ <td>351</td>
+ <td>682.4</td>
+ <td>John</td>
+ <td>$53.64</td>
+
+ <td>2009-01-17</td>
+ </tr>
+ <tr>
+ <td>352</td>
+ <td>805.3</td>
+ <td>Phil</td>
+ <td>$20.74</td>
+
+ <td>2009-08-24</td>
+ </tr>
+ <tr>
+ <td>353</td>
+ <td>836</td>
+ <td>Jack</td>
+ <td>$36.94</td>
+
+ <td>2010-08-05</td>
+ </tr>
+ <tr>
+ <td>354</td>
+ <td>848.6</td>
+ <td>Paul</td>
+ <td>$95.74</td>
+
+ <td>2010-04-23</td>
+ </tr>
+ <tr>
+ <td>355</td>
+ <td>201</td>
+ <td>Rob</td>
+ <td>$90.74</td>
+
+ <td>2009-05-26</td>
+ </tr>
+ <tr>
+ <td>356</td>
+ <td>880.9</td>
+ <td>Walt</td>
+ <td>$59.74</td>
+
+ <td>2010-09-16</td>
+ </tr>
+ <tr>
+ <td>357</td>
+ <td>762.2</td>
+ <td>Nathan</td>
+ <td>$92.74</td>
+
+ <td>2008-05-29</td>
+ </tr>
+ <tr>
+ <td>358</td>
+ <td>763.1</td>
+ <td>Dan</td>
+ <td>$71.24</td>
+
+ <td>2010-04-21</td>
+ </tr>
+ <tr>
+ <td>359</td>
+ <td>226.4</td>
+ <td>Jeff</td>
+ <td>$76.54</td>
+
+ <td>2009-04-18</td>
+ </tr>
+ <tr>
+ <td>360</td>
+ <td>960.8</td>
+ <td>Bill</td>
+ <td>$13.54</td>
+
+ <td>2009-11-02</td>
+ </tr>
+ <tr>
+ <td>361</td>
+ <td>386.9</td>
+ <td>Joe</td>
+ <td>$81.74</td>
+
+ <td>2008-05-14</td>
+ </tr>
+ <tr>
+ <td>362</td>
+ <td>727.6</td>
+ <td>Bob</td>
+ <td>$62.34</td>
+
+ <td>2009-01-08</td>
+ </tr>
+ <tr>
+ <td>363</td>
+ <td>257.8</td>
+ <td>Matt</td>
+ <td>$45.94</td>
+
+ <td>2010-03-11</td>
+ </tr>
+ <tr>
+ <td>364</td>
+ <td>87</td>
+ <td>Mark</td>
+ <td>$30.74</td>
+
+ <td>2010-01-20</td>
+ </tr>
+ <tr>
+ <td>365</td>
+ <td>826</td>
+ <td>Tom</td>
+ <td>$50.84</td>
+
+ <td>2009-10-05</td>
+ </tr>
+ <tr>
+ <td>366</td>
+ <td>278.6</td>
+ <td>Jake</td>
+ <td>$38.94</td>
+
+ <td>2008-06-25</td>
+ </tr>
+ <tr>
+ <td>367</td>
+ <td>144.2</td>
+ <td>Greg</td>
+ <td>$15.14</td>
+
+ <td>2008-04-02</td>
+ </tr>
+ <tr>
+ <td>368</td>
+ <td>284.2</td>
+ <td>Adam</td>
+ <td>$91.44</td>
+
+ <td>2010-07-05</td>
+ </tr>
+ <tr>
+ <td>369</td>
+ <td>22</td>
+ <td>Steve</td>
+ <td>$14.14</td>
+
+ <td>2009-10-07</td>
+ </tr>
+ <tr>
+ <td>370</td>
+ <td>441.8</td>
+ <td>George</td>
+ <td>$10.14</td>
+
+ <td>2010-03-12</td>
+ </tr>
+ <tr>
+ <td>371</td>
+ <td>32.2</td>
+ <td>John</td>
+ <td>$48.84</td>
+
+ <td>2009-08-13</td>
+ </tr>
+ <tr>
+ <td>372</td>
+ <td>158.8</td>
+ <td>Phil</td>
+ <td>$21.64</td>
+
+ <td>2008-06-02</td>
+ </tr>
+ <tr>
+ <td>373</td>
+ <td>492.4</td>
+ <td>Jack</td>
+ <td>$47.34</td>
+
+ <td>2009-11-14</td>
+ </tr>
+ <tr>
+ <td>374</td>
+ <td>194.4</td>
+ <td>Paul</td>
+ <td>$56.04</td>
+
+ <td>2010-11-05</td>
+ </tr>
+ <tr>
+ <td>375</td>
+ <td>853.5</td>
+ <td>Rob</td>
+ <td>$38.64</td>
+
+ <td>2009-04-14</td>
+ </tr>
+ <tr>
+ <td>376</td>
+ <td>420</td>
+ <td>Walt</td>
+ <td>$66.54</td>
+
+ <td>2010-07-09</td>
+ </tr>
+ <tr>
+ <td>377</td>
+ <td>583.4</td>
+ <td>Nathan</td>
+ <td>$80.94</td>
+
+ <td>2010-12-30</td>
+ </tr>
+ <tr>
+ <td>378</td>
+ <td>674</td>
+ <td>Dan</td>
+ <td>$9.33</td>
+
+ <td>2010-09-22</td>
+ </tr>
+ <tr>
+ <td>379</td>
+ <td>476.8</td>
+ <td>Jeff</td>
+ <td>$11.54</td>
+
+ <td>2008-01-01</td>
+ </tr>
+ <tr>
+ <td>380</td>
+ <td>44.9</td>
+ <td>Bill</td>
+ <td>$55.74</td>
+
+ <td>2008-04-27</td>
+ </tr>
+ <tr>
+ <td>381</td>
+ <td>748</td>
+ <td>Joe</td>
+ <td>$58.94</td>
+
+ <td>2009-11-13</td>
+ </tr>
+ <tr>
+ <td>382</td>
+ <td>268.4</td>
+ <td>Bob</td>
+ <td>$74.84</td>
+
+ <td>2010-07-21</td>
+ </tr>
+ <tr>
+ <td>383</td>
+ <td>411.3</td>
+ <td>Matt</td>
+ <td>$24.04</td>
+
+ <td>2008-11-18</td>
+ </tr>
+ <tr>
+ <td>384</td>
+ <td>12.8</td>
+ <td>Mark</td>
+ <td>$43.44</td>
+
+ <td>2010-08-29</td>
+ </tr>
+ <tr>
+ <td>385</td>
+ <td>921.3</td>
+ <td>Tom</td>
+ <td>$28.84</td>
+
+ <td>2008-09-18</td>
+ </tr>
+ <tr>
+ <td>386</td>
+ <td>337.8</td>
+ <td>Jake</td>
+ <td>$70.84</td>
+
+ <td>2010-10-27</td>
+ </tr>
+ <tr>
+ <td>387</td>
+ <td>143.3</td>
+ <td>Greg</td>
+ <td>$29.14</td>
+
+ <td>2010-03-20</td>
+ </tr>
+ <tr>
+ <td>388</td>
+ <td>99.8</td>
+ <td>Adam</td>
+ <td>$96.54</td>
+
+ <td>2010-07-06</td>
+ </tr>
+ <tr>
+ <td>389</td>
+ <td>970.4</td>
+ <td>Steve</td>
+ <td>$44.24</td>
+
+ <td>2010-11-16</td>
+ </tr>
+ <tr>
+ <td>390</td>
+ <td>981.5</td>
+ <td>George</td>
+ <td>$48.74</td>
+
+ <td>2009-06-21</td>
+ </tr>
+ <tr>
+ <td>391</td>
+ <td>93.8</td>
+ <td>John</td>
+ <td>$23.44</td>
+
+ <td>2008-03-02</td>
+ </tr>
+ <tr>
+ <td>392</td>
+ <td>694.2</td>
+ <td>Phil</td>
+ <td>$50.34</td>
+
+ <td>2010-07-16</td>
+ </tr>
+ <tr>
+ <td>393</td>
+ <td>510.3</td>
+ <td>Jack</td>
+ <td>$91.44</td>
+
+ <td>2008-02-17</td>
+ </tr>
+ <tr>
+ <td>394</td>
+ <td>799.7</td>
+ <td>Paul</td>
+ <td>$92.74</td>
+
+ <td>2009-07-04</td>
+ </tr>
+ <tr>
+ <td>395</td>
+ <td>649.5</td>
+ <td>Rob</td>
+ <td>$84.84</td>
+
+ <td>2010-06-02</td>
+ </tr>
+ <tr>
+ <td>396</td>
+ <td>885.6</td>
+ <td>Walt</td>
+ <td>$18.64</td>
+
+ <td>2009-06-28</td>
+ </tr>
+ <tr>
+ <td>397</td>
+ <td>786.6</td>
+ <td>Nathan</td>
+ <td>$32.94</td>
+
+ <td>2010-05-31</td>
+ </tr>
+ <tr>
+ <td>398</td>
+ <td>496.7</td>
+ <td>Dan</td>
+ <td>$42.94</td>
+
+ <td>2010-04-21</td>
+ </tr>
+ <tr>
+ <td>399</td>
+ <td>299.9</td>
+ <td>Jeff</td>
+ <td>$39.94</td>
+
+ <td>2008-07-13</td>
+ </tr>
+ <tr>
+ <td>400</td>
+ <td>218.1</td>
+ <td>Bill</td>
+ <td>$38.14</td>
+
+ <td>2010-01-27</td>
+ </tr>
+ <tr>
+ <td>401</td>
+ <td>693.2</td>
+ <td>Joe</td>
+ <td>$47.44</td>
+
+ <td>2010-10-26</td>
+ </tr>
+ <tr>
+ <td>402</td>
+ <td>757.2</td>
+ <td>Bob</td>
+ <td>$16.94</td>
+
+ <td>2009-03-29</td>
+ </tr>
+ <tr>
+ <td>403</td>
+ <td>568.9</td>
+ <td>Matt</td>
+ <td>$67.94</td>
+
+ <td>2008-12-20</td>
+ </tr>
+ <tr>
+ <td>404</td>
+ <td>620.5</td>
+ <td>Mark</td>
+ <td>$47.84</td>
+
+ <td>2008-09-26</td>
+ </tr>
+ <tr>
+ <td>405</td>
+ <td>106.4</td>
+ <td>Tom</td>
+ <td>$12.84</td>
+
+ <td>2008-04-04</td>
+ </tr>
+ <tr>
+ <td>406</td>
+ <td>880.1</td>
+ <td>Jake</td>
+ <td>$1.33</td>
+
+ <td>2008-11-05</td>
+ </tr>
+ <tr>
+ <td>407</td>
+ <td>361.5</td>
+ <td>Greg</td>
+ <td>$80.04</td>
+
+ <td>2009-11-20</td>
+ </tr>
+ <tr>
+ <td>408</td>
+ <td>133.8</td>
+ <td>Adam</td>
+ <td>$29.74</td>
+
+ <td>2008-01-29</td>
+ </tr>
+ <tr>
+ <td>409</td>
+ <td>871.1</td>
+ <td>Steve</td>
+ <td>$59.64</td>
+
+ <td>2009-05-05</td>
+ </tr>
+ <tr>
+ <td>410</td>
+ <td>50</td>
+ <td>George</td>
+ <td>$81.54</td>
+
+ <td>2010-07-20</td>
+ </tr>
+ <tr>
+ <td>411</td>
+ <td>715.4</td>
+ <td>John</td>
+ <td>$50.84</td>
+
+ <td>2008-11-18</td>
+ </tr>
+ <tr>
+ <td>412</td>
+ <td>615.3</td>
+ <td>Phil</td>
+ <td>$26.54</td>
+
+ <td>2009-06-01</td>
+ </tr>
+ <tr>
+ <td>413</td>
+ <td>18.1</td>
+ <td>Jack</td>
+ <td>$83.44</td>
+
+ <td>2008-05-25</td>
+ </tr>
+ <tr>
+ <td>414</td>
+ <td>335</td>
+ <td>Paul</td>
+ <td>$45.44</td>
+
+ <td>2009-11-30</td>
+ </tr>
+ <tr>
+ <td>415</td>
+ <td>578.7</td>
+ <td>Rob</td>
+ <td>$56.04</td>
+
+ <td>2010-04-27</td>
+ </tr>
+ <tr>
+ <td>416</td>
+ <td>670.5</td>
+ <td>Walt</td>
+ <td>$44.04</td>
+
+ <td>2010-05-12</td>
+ </tr>
+ <tr>
+ <td>417</td>
+ <td>948.2</td>
+ <td>Nathan</td>
+ <td>$80.24</td>
+
+ <td>2009-09-23</td>
+ </tr>
+ <tr>
+ <td>418</td>
+ <td>554.8</td>
+ <td>Dan</td>
+ <td>$93.64</td>
+
+ <td>2010-09-01</td>
+ </tr>
+ <tr>
+ <td>419</td>
+ <td>590.3</td>
+ <td>Jeff</td>
+ <td>$80.74</td>
+
+ <td>2009-05-22</td>
+ </tr>
+ <tr>
+ <td>420</td>
+ <td>24.8</td>
+ <td>Bill</td>
+ <td>$85.74</td>
+
+ <td>2008-10-19</td>
+ </tr>
+ <tr>
+ <td>421</td>
+ <td>839.9</td>
+ <td>Joe</td>
+ <td>$57.24</td>
+
+ <td>2010-05-29</td>
+ </tr>
+ <tr>
+ <td>422</td>
+ <td>129.3</td>
+ <td>Bob</td>
+ <td>$18.74</td>
+
+ <td>2008-01-29</td>
+ </tr>
+ <tr>
+ <td>423</td>
+ <td>587.2</td>
+ <td>Matt</td>
+ <td>$20.54</td>
+
+ <td>2010-09-20</td>
+ </tr>
+ <tr>
+ <td>424</td>
+ <td>723.7</td>
+ <td>Mark</td>
+ <td>$54.04</td>
+
+ <td>2008-12-27</td>
+ </tr>
+ <tr>
+ <td>425</td>
+ <td>338.5</td>
+ <td>Tom</td>
+ <td>$11.94</td>
+
+ <td>2010-10-07</td>
+ </tr>
+ <tr>
+ <td>426</td>
+ <td>81</td>
+ <td>Jake</td>
+ <td>$78.94</td>
+
+ <td>2008-12-28</td>
+ </tr>
+ <tr>
+ <td>427</td>
+ <td>836.9</td>
+ <td>Greg</td>
+ <td>$73.84</td>
+
+ <td>2008-05-13</td>
+ </tr>
+ <tr>
+ <td>428</td>
+ <td>392.7</td>
+ <td>Adam</td>
+ <td>$29.24</td>
+
+ <td>2008-02-29</td>
+ </tr>
+ <tr>
+ <td>429</td>
+ <td>245</td>
+ <td>Steve</td>
+ <td>$88.34</td>
+
+ <td>2010-09-19</td>
+ </tr>
+ <tr>
+ <td>430</td>
+ <td>693.7</td>
+ <td>George</td>
+ <td>$90.74</td>
+
+ <td>2010-04-06</td>
+ </tr>
+ <tr>
+ <td>431</td>
+ <td>956.8</td>
+ <td>John</td>
+ <td>$74.74</td>
+
+ <td>2008-11-27</td>
+ </tr>
+ <tr>
+ <td>432</td>
+ <td>727.5</td>
+ <td>Phil</td>
+ <td>$87.74</td>
+
+ <td>2009-07-02</td>
+ </tr>
+ <tr>
+ <td>433</td>
+ <td>763</td>
+ <td>Jack</td>
+ <td>$46.44</td>
+
+ <td>2010-02-24</td>
+ </tr>
+ <tr>
+ <td>434</td>
+ <td>632</td>
+ <td>Paul</td>
+ <td>$18.74</td>
+
+ <td>2008-09-10</td>
+ </tr>
+ <tr>
+ <td>435</td>
+ <td>955.1</td>
+ <td>Rob</td>
+ <td>$52.64</td>
+
+ <td>2009-01-26</td>
+ </tr>
+ <tr>
+ <td>436</td>
+ <td>838.7</td>
+ <td>Walt</td>
+ <td>$60.74</td>
+
+ <td>2008-05-27</td>
+ </tr>
+ <tr>
+ <td>437</td>
+ <td>162.7</td>
+ <td>Nathan</td>
+ <td>$44.44</td>
+
+ <td>2010-09-27</td>
+ </tr>
+ <tr>
+ <td>438</td>
+ <td>288.6</td>
+ <td>Dan</td>
+ <td>$83.64</td>
+
+ <td>2008-06-30</td>
+ </tr>
+ <tr>
+ <td>439</td>
+ <td>350.1</td>
+ <td>Jeff</td>
+ <td>$8.13</td>
+
+ <td>2008-02-15</td>
+ </tr>
+ <tr>
+ <td>440</td>
+ <td>218.4</td>
+ <td>Bill</td>
+ <td>$77.54</td>
+
+ <td>2010-12-31</td>
+ </tr>
+ <tr>
+ <td>441</td>
+ <td>943.2</td>
+ <td>Joe</td>
+ <td>$73.14</td>
+
+ <td>2010-03-14</td>
+ </tr>
+ <tr>
+ <td>442</td>
+ <td>240</td>
+ <td>Bob</td>
+ <td>$45.94</td>
+
+ <td>2009-10-22</td>
+ </tr>
+ <tr>
+ <td>443</td>
+ <td>724</td>
+ <td>Matt</td>
+ <td>$22.24</td>
+
+ <td>2008-02-09</td>
+ </tr>
+ <tr>
+ <td>444</td>
+ <td>413.3</td>
+ <td>Mark</td>
+ <td>$85.44</td>
+
+ <td>2008-09-13</td>
+ </tr>
+ <tr>
+ <td>445</td>
+ <td>642.8</td>
+ <td>Tom</td>
+ <td>$80.94</td>
+
+ <td>2010-05-14</td>
+ </tr>
+ <tr>
+ <td>446</td>
+ <td>991.3</td>
+ <td>Jake</td>
+ <td>$64.84</td>
+
+ <td>2009-02-13</td>
+ </tr>
+ <tr>
+ <td>447</td>
+ <td>129.2</td>
+ <td>Greg</td>
+ <td>$81.04</td>
+
+ <td>2010-07-11</td>
+ </tr>
+ <tr>
+ <td>448</td>
+ <td>4.6</td>
+ <td>Adam</td>
+ <td>$9.93</td>
+
+ <td>2010-01-02</td>
+ </tr>
+ <tr>
+ <td>449</td>
+ <td>172.2</td>
+ <td>Steve</td>
+ <td>$44.94</td>
+
+ <td>2010-04-06</td>
+ </tr>
+ <tr>
+ <td>450</td>
+ <td>222.3</td>
+ <td>George</td>
+ <td>$66.74</td>
+
+ <td>2009-07-19</td>
+ </tr>
+ <tr>
+ <td>451</td>
+ <td>179.7</td>
+ <td>John</td>
+ <td>$61.04</td>
+
+ <td>2008-09-11</td>
+ </tr>
+ <tr>
+ <td>452</td>
+ <td>884.3</td>
+ <td>Phil</td>
+ <td>$85.04</td>
+
+ <td>2010-02-24</td>
+ </tr>
+ <tr>
+ <td>453</td>
+ <td>465.3</td>
+ <td>Jack</td>
+ <td>$57.44</td>
+
+ <td>2010-11-08</td>
+ </tr>
+ <tr>
+ <td>454</td>
+ <td>510</td>
+ <td>Paul</td>
+ <td>$98.74</td>
+
+ <td>2010-05-22</td>
+ </tr>
+ <tr>
+ <td>455</td>
+ <td>741.8</td>
+ <td>Rob</td>
+ <td>$63.04</td>
+
+ <td>2009-10-13</td>
+ </tr>
+ <tr>
+ <td>456</td>
+ <td>499.2</td>
+ <td>Walt</td>
+ <td>$62.14</td>
+
+ <td>2008-08-31</td>
+ </tr>
+ <tr>
+ <td>457</td>
+ <td>863.3</td>
+ <td>Nathan</td>
+ <td>$75.04</td>
+
+ <td>2008-01-24</td>
+ </tr>
+ <tr>
+ <td>458</td>
+ <td>670.7</td>
+ <td>Dan</td>
+ <td>$75.54</td>
+
+ <td>2008-05-17</td>
+ </tr>
+ <tr>
+ <td>459</td>
+ <td>314.2</td>
+ <td>Jeff</td>
+ <td>$92.74</td>
+
+ <td>2009-10-19</td>
+ </tr>
+ <tr>
+ <td>460</td>
+ <td>38.7</td>
+ <td>Bill</td>
+ <td>$14.94</td>
+
+ <td>2008-09-28</td>
+ </tr>
+ <tr>
+ <td>461</td>
+ <td>537.8</td>
+ <td>Joe</td>
+ <td>$32.94</td>
+
+ <td>2010-09-05</td>
+ </tr>
+ <tr>
+ <td>462</td>
+ <td>768.2</td>
+ <td>Bob</td>
+ <td>$21.34</td>
+
+ <td>2010-03-15</td>
+ </tr>
+ <tr>
+ <td>463</td>
+ <td>457.5</td>
+ <td>Matt</td>
+ <td>$67.94</td>
+
+ <td>2008-11-07</td>
+ </tr>
+ <tr>
+ <td>464</td>
+ <td>368.5</td>
+ <td>Mark</td>
+ <td>$18.94</td>
+
+ <td>2008-10-23</td>
+ </tr>
+ <tr>
+ <td>465</td>
+ <td>133.3</td>
+ <td>Tom</td>
+ <td>$93.04</td>
+
+ <td>2010-10-22</td>
+ </tr>
+ <tr>
+ <td>466</td>
+ <td>706.9</td>
+ <td>Jake</td>
+ <td>$43.04</td>
+
+ <td>2009-08-10</td>
+ </tr>
+ <tr>
+ <td>467</td>
+ <td>927.9</td>
+ <td>Greg</td>
+ <td>$29.34</td>
+
+ <td>2008-10-25</td>
+ </tr>
+ <tr>
+ <td>468</td>
+ <td>959.1</td>
+ <td>Adam</td>
+ <td>$96.34</td>
+
+ <td>2008-01-16</td>
+ </tr>
+ <tr>
+ <td>469</td>
+ <td>88.8</td>
+ <td>Steve</td>
+ <td>$27.84</td>
+
+ <td>2010-12-24</td>
+ </tr>
+ <tr>
+ <td>470</td>
+ <td>667.2</td>
+ <td>George</td>
+ <td>$31.64</td>
+
+ <td>2008-04-13</td>
+ </tr>
+ <tr>
+ <td>471</td>
+ <td>912.6</td>
+ <td>John</td>
+ <td>$85.44</td>
+
+ <td>2009-04-29</td>
+ </tr>
+ <tr>
+ <td>472</td>
+ <td>768.1</td>
+ <td>Phil</td>
+ <td>$62.24</td>
+
+ <td>2010-01-01</td>
+ </tr>
+ <tr>
+ <td>473</td>
+ <td>473.8</td>
+ <td>Jack</td>
+ <td>$8.03</td>
+
+ <td>2008-12-25</td>
+ </tr>
+ <tr>
+ <td>474</td>
+ <td>753.4</td>
+ <td>Paul</td>
+ <td>$44.84</td>
+
+ <td>2009-07-31</td>
+ </tr>
+ <tr>
+ <td>475</td>
+ <td>20.3</td>
+ <td>Rob</td>
+ <td>$58.14</td>
+
+ <td>2009-05-11</td>
+ </tr>
+ <tr>
+ <td>476</td>
+ <td>917.3</td>
+ <td>Walt</td>
+ <td>$28.84</td>
+
+ <td>2010-09-20</td>
+ </tr>
+ <tr>
+ <td>477</td>
+ <td>435.6</td>
+ <td>Nathan</td>
+ <td>$21.64</td>
+
+ <td>2008-06-24</td>
+ </tr>
+ <tr>
+ <td>478</td>
+ <td>704.3</td>
+ <td>Dan</td>
+ <td>$17.54</td>
+
+ <td>2008-05-12</td>
+ </tr>
+ <tr>
+ <td>479</td>
+ <td>728.1</td>
+ <td>Jeff</td>
+ <td>$26.44</td>
+
+ <td>2009-03-29</td>
+ </tr>
+ <tr>
+ <td>480</td>
+ <td>678.9</td>
+ <td>Bill</td>
+ <td>$93.14</td>
+
+ <td>2010-03-30</td>
+ </tr>
+ <tr>
+ <td>481</td>
+ <td>779.1</td>
+ <td>Joe</td>
+ <td>$84.34</td>
+
+ <td>2009-10-12</td>
+ </tr>
+ <tr>
+ <td>482</td>
+ <td>208.3</td>
+ <td>Bob</td>
+ <td>$61.14</td>
+
+ <td>2008-07-31</td>
+ </tr>
+ <tr>
+ <td>483</td>
+ <td>850.8</td>
+ <td>Matt</td>
+ <td>$8.53</td>
+
+ <td>2008-10-31</td>
+ </tr>
+ <tr>
+ <td>484</td>
+ <td>171.8</td>
+ <td>Mark</td>
+ <td>$83.84</td>
+
+ <td>2010-04-03</td>
+ </tr>
+ <tr>
+ <td>485</td>
+ <td>681.4</td>
+ <td>Tom</td>
+ <td>$85.94</td>
+
+ <td>2008-12-04</td>
+ </tr>
+ <tr>
+ <td>486</td>
+ <td>121.1</td>
+ <td>Jake</td>
+ <td>$77.64</td>
+
+ <td>2009-11-02</td>
+ </tr>
+ <tr>
+ <td>487</td>
+ <td>990.2</td>
+ <td>Greg</td>
+ <td>$21.14</td>
+
+ <td>2010-07-10</td>
+ </tr>
+ <tr>
+ <td>488</td>
+ <td>152</td>
+ <td>Adam</td>
+ <td>$91.64</td>
+
+ <td>2011-01-28</td>
+ </tr>
+ <tr>
+ <td>489</td>
+ <td>277</td>
+ <td>Steve</td>
+ <td>$64.44</td>
+
+ <td>2008-09-28</td>
+ </tr>
+ <tr>
+ <td>490</td>
+ <td>679.5</td>
+ <td>George</td>
+ <td>$32.34</td>
+
+ <td>2008-07-10</td>
+ </tr>
+ <tr>
+ <td>491</td>
+ <td>398</td>
+ <td>John</td>
+ <td>$10.24</td>
+
+ <td>2008-01-10</td>
+ </tr>
+ <tr>
+ <td>492</td>
+ <td>970.4</td>
+ <td>Phil</td>
+ <td>$31.04</td>
+
+ <td>2009-12-18</td>
+ </tr>
+ <tr>
+ <td>493</td>
+ <td>164.7</td>
+ <td>Jack</td>
+ <td>$16.14</td>
+
+ <td>2010-03-26</td>
+ </tr>
+ <tr>
+ <td>494</td>
+ <td>438.5</td>
+ <td>Paul</td>
+ <td>$33.24</td>
+
+ <td>2009-09-20</td>
+ </tr>
+ <tr>
+ <td>495</td>
+ <td>160.2</td>
+ <td>Rob</td>
+ <td>$1.43</td>
+
+ <td>2009-04-10</td>
+ </tr>
+ <tr>
+ <td>496</td>
+ <td>463</td>
+ <td>Walt</td>
+ <td>$13.54</td>
+
+ <td>2008-07-24</td>
+ </tr>
+ <tr>
+ <td>497</td>
+ <td>53.9</td>
+ <td>Nathan</td>
+ <td>$12.54</td>
+
+ <td>2009-03-26</td>
+ </tr>
+ <tr>
+ <td>498</td>
+ <td>860.6</td>
+ <td>Dan</td>
+ <td>$27.74</td>
+
+ <td>2008-12-18</td>
+ </tr>
+ <tr>
+ <td>499</td>
+ <td>842.2</td>
+ <td>Jeff</td>
+ <td>$55.44</td>
+
+ <td>2011-01-02</td>
+ </tr>
+ </tbody>
+ </table>
+ </body>
+ </head>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/demo_Templated.html b/includes/js/dojox/dtl/demos/demo_Templated.html
new file mode 100644
index 0000000..b538811
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Templated.html
@@ -0,0 +1,36 @@
+<html>
+ <head>
+ <title>Demo using dojox.dtl._Templated</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../../dijit/dijit.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl._Templated");
+
+ dojo.declare("Fruit", [dijit._Widget, dojox.dtl._Templated], {
+ oldRepl: "Fruit: ",
+ _dijitTemplateCompat: true,
+ items: ["apple", "banana", "orange"],
+ keyUp: function(e){
+ if(e.keyCode == dojo.keys.ENTER){
+ var i = dojo.indexOf(this.items, e.target.value);
+ if(i != -1){
+ this.items.splice(i, 1);
+ }else{
+ this.items.push(e.target.value);
+ }
+ e.target.value = "";
+ this.render();
+ dojo.query("input", this.domNode).forEach("item.focus();");
+ }
+ },
+ templateString: '<div><input dojoAttachEvent="onkeyup: keyUp"><ul>{% for item in items %}<li>${oldRepl} {{ item }}</li>{% endfor %}</ul></div>'
+ });
+
+ dojo.require("dojo.parser");
+ </script>
+ <body>
+ <div dojoType="Fruit"></div>
+ </body>
+ </head>
+</html>
diff --git a/includes/js/dojox/dtl/demos/demo_Tree.html b/includes/js/dojox/dtl/demos/demo_Tree.html
new file mode 100644
index 0000000..692d863
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/demo_Tree.html
@@ -0,0 +1,33 @@
+<html>
+ <head>
+ <title>Demo to show recursion in DTL</title>
+ <script type="text/javascript" src="../../../dojo/dojo.js"
+ djConfig="isDebug: true, parseOnLoad: true"></script>
+ <script type="text/javascript" src="../../../dijit/dijit.js"></script>
+ <script type="text/javascript">
+ dojo.require("dojox.dtl._HtmlTemplated");
+ dojo.require("dojo.data.ItemFileReadStore");
+ dojo.require("dojo.parser");
+
+ dojo.declare("demo.Tree", [dijit._Widget, dojox.dtl._HtmlTemplated], {
+ store: new dojo.data.ItemFileReadStore({ url: dojo.moduleUrl("dijit.tests._data", "countries.json") }),
+ countrychildren: dojo.moduleUrl("dojox.dtl.demos.templates", "countrychildren.html"),
+ postCreate: function(){
+ this.store.fetch({
+ query: {
+ type: "continent"
+ },
+ onComplete: dojo.hitch(this, function(items){
+ this.items = items;
+ this.render();
+ })
+ });
+ },
+ templateString: '{% load dojox.dtl.contrib.data %}{% bind_data items to store as countries %}<ul>{% for country in countries %}{% include countrychildren %}{% endfor %}</ul>'
+ });
+ </script>
+ <body>
+ <div dojoType="demo.Tree"></div>
+ </body>
+ </head>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/json/blog/get_blog_1.json b/includes/js/dojox/dtl/demos/json/blog/get_blog_1.json
new file mode 100644
index 0000000..9c7dd9f
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/json/blog/get_blog_1.json
@@ -0,0 +1 @@
+{"teaser":"I'd be able to write a lot faster.","body":"I think I wouldn't be able to think.","date":1189125242601,"author":"jim"} \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/json/blog/get_blog_3.json b/includes/js/dojox/dtl/demos/json/blog/get_blog_3.json
new file mode 100644
index 0000000..7c0a937
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/json/blog/get_blog_3.json
@@ -0,0 +1 @@
+{"teaser":"There was SO much sand","body":"I tried to walk so fast that I wouldn't leave foot prints.","date":1190245842601,"author":"jim"} \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/json/blog/get_blog_list.json b/includes/js/dojox/dtl/demos/json/blog/get_blog_list.json
new file mode 100644
index 0000000..40f14a7
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/json/blog/get_blog_list.json
@@ -0,0 +1 @@
+{"blog_list":{"3":{"title":"My Trip to the Beach"},"1":{"title":"If I Were a Robot"}}} \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/json/blog/get_page_about.json b/includes/js/dojox/dtl/demos/json/blog/get_page_about.json
new file mode 100644
index 0000000..05ddb9c
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/json/blog/get_page_about.json
@@ -0,0 +1 @@
+{"title":"About Jim","body":"<p>Jim is an avid golfer, enjoys long walks on the beach, and eating hot pockets</p><p>When he's not scalding his mouth, you'll find him throwing rocks at pigeons.</p>"} \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/json/fruit.json b/includes/js/dojox/dtl/demos/json/fruit.json
new file mode 100644
index 0000000..e7a0bf8
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/json/fruit.json
@@ -0,0 +1 @@
+{ items: ["apple", "banana", "pear"] } \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/json/morefruit.json b/includes/js/dojox/dtl/demos/json/morefruit.json
new file mode 100644
index 0000000..6a8beea
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/json/morefruit.json
@@ -0,0 +1 @@
+{ items: ["pineapple", "orange", "tomato"] } \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/animation.html b/includes/js/dojox/dtl/demos/templates/animation.html
new file mode 100644
index 0000000..56c38f3
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/animation.html
@@ -0,0 +1,5 @@
+{% load dojox.dtl.contrib.dijit dojox.dtl.contrib.html %}
+<div>
+ <div tstyle="top: {{ y }}px; left: {{ x }}px;" style="width: 10px; height: 10px; background: red; position: absolute;">&nbsp;</div>
+ <div dojoAttachPoint="blue" style="top: 10px; left: 0; width: 10px; height: 10px; background: blue; position: absolute;">&nbsp;</div>
+</div> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/blog_base.html b/includes/js/dojox/dtl/demos/templates/blog_base.html
new file mode 100644
index 0000000..1438a6b
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/blog_base.html
@@ -0,0 +1,8 @@
+<div>
+ <h1><!--{{ title }}--></h1>
+ <ul style="float: left; width: 100px; height: 300px; margin-right: 20px; border: 1px solid #666;">
+ <li><a onclick="_showList" style="cursor: pointer;">Home</a></li>
+ <li><a onclick="_showPage" style="cursor: pointer;" class="page-about">About Jim</a></li>
+ </ul>
+ <!--{% block body %}--><!--{% endblock %}-->
+</div> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/blog_detail.html b/includes/js/dojox/dtl/demos/templates/blog_detail.html
new file mode 100644
index 0000000..2b6146d
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/blog_detail.html
@@ -0,0 +1,10 @@
+<!--{% extends base %}-->
+
+<!--{% block body %}-->
+<div>
+<h3><!--{{ blog.title }}--></h3>
+<div><small>posted on <!--{{ blog.date|date }}--> by <!--{{ blog.author }}--></small></div>
+<p><!--{{ blog.teaser }}--></p>
+<p><!--{{ blog.body }}--></p>
+</div>
+<!--{% endblock %}--> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/blog_list.html b/includes/js/dojox/dtl/demos/templates/blog_list.html
new file mode 100644
index 0000000..2413605
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/blog_list.html
@@ -0,0 +1,9 @@
+<!--{% extends base %}-->
+<!--{% load dojox.dtl.contrib.dijit %}-->
+<!--{% block body %}-->
+<ul>
+<!--{% for key, blog in blog_list.items %}-->
+<li onclick="_showDetail" class="blog-{{ key }}" style="cursor: pointer;">{{ blog.title }}</li>
+<!--{% endfor %}-->
+</ul>
+<!--{% endblock %}--> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/blog_page.html b/includes/js/dojox/dtl/demos/templates/blog_page.html
new file mode 100644
index 0000000..aeeb762
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/blog_page.html
@@ -0,0 +1,7 @@
+<!--{% extends "shared:templates/blog_base.html" %}-->
+<!--{% load dojox.dtl.contrib.html %}-->
+<!--{% block body %}-->
+<div>
+ <!--{% html body %}-->
+</div>
+<!--{% endblock %}--> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/countrychildren.html b/includes/js/dojox/dtl/demos/templates/countrychildren.html
new file mode 100644
index 0000000..fbdbebe
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/countrychildren.html
@@ -0,0 +1 @@
+<li>{{ country.type }}: {{ country.name }}{% if country.children %}<ul>{% for country in country.childrens %}{% include countrychildren %}{% endfor %}</ul>{% endif %}</li> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/gallery.html b/includes/js/dojox/dtl/demos/templates/gallery.html
new file mode 100644
index 0000000..7fe6d8c
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/gallery.html
@@ -0,0 +1,16 @@
+{% load dojox.dtl.contrib.data %}
+{% bind_data items to store as flickr %}
+<div>
+ <input dojoAttachEvent="onkeypress: keyUp">
+ <table>
+ <tr>
+ {% for item in flickr %}<td><img src="{{ item.imageUrlThumb }}" dojoAttachEvent="onclick: selectThumbnail" class="{{ item.imageUrl }}" /></td>{% endfor %}
+ <td width="100%"></td>
+ </tr>
+ <tr>
+ <td colspan="{{ flickr|length|add:1 }}">
+ {% if selected %}<img src="{{ selected }}" />{% endif %}
+ </td>
+ </tr>
+ </table>
+</div> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/demos/templates/nodelist.html b/includes/js/dojox/dtl/demos/templates/nodelist.html
new file mode 100644
index 0000000..ddf7def
--- /dev/null
+++ b/includes/js/dojox/dtl/demos/templates/nodelist.html
@@ -0,0 +1,5 @@
+<div>
+ <ul>
+ {% for item in items %}<li>{{ item }}</li>{% endfor %}
+ </ul>
+</div> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/ext-dojo/NodeList.js b/includes/js/dojox/dtl/ext-dojo/NodeList.js
new file mode 100644
index 0000000..64e9a93
--- /dev/null
+++ b/includes/js/dojox/dtl/ext-dojo/NodeList.js
@@ -0,0 +1,33 @@
+if(!dojo._hasResource["dojox.dtl.ext-dojo.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.ext-dojo.NodeList"] = true;
+dojo.provide("dojox.dtl.ext-dojo.NodeList");
+dojo.require("dojox.dtl._base");
+
+dojo.extend(dojo.NodeList, {
+ dtl: function(template, context){
+ // args: dojox.dtl.__StringArgs|String
+ // The template string or location
+ // context: dojox.dtl.__ObjectArgs|Object
+ // The context object or location
+ var d = dojox.dtl;
+
+ var self = this;
+ var render = function(data){
+ var content = template.render(new d._Context(context));
+ self.forEach(function(node){
+ node.innerHTML = content;
+ });
+ }
+
+ d.text._resolveTemplateArg(template).addCallback(function(templateString){
+ template = new d.Template(templateString);
+ d.text._resolveContextArg(context).addCallback(function(contextObject){
+ render(contextObject);
+ });
+ });
+
+ return this;
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/filter/dates.js b/includes/js/dojox/dtl/filter/dates.js
new file mode 100644
index 0000000..3ca2022
--- /dev/null
+++ b/includes/js/dojox/dtl/filter/dates.js
@@ -0,0 +1,54 @@
+if(!dojo._hasResource["dojox.dtl.filter.dates"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.filter.dates"] = true;
+dojo.provide("dojox.dtl.filter.dates");
+
+dojo.require("dojox.dtl.utils.date");
+
+(function(){
+ var ddfd = dojox.dtl.filter.dates;
+
+ dojo.mixin(ddfd, {
+ _toDate: function(value){
+ if(value instanceof Date){
+ return value;
+ }
+ value = new Date(value);
+ if(value.getTime() == new Date(0).getTime()){
+ return "";
+ }
+ return value;
+ },
+ date: function(value, arg){
+ // summary: Formats a date according to the given format
+ value = ddfd._toDate(value);
+ if(!value) return "";
+ arg = arg || "N j, Y";
+ return dojox.dtl.utils.date.format(value, arg);
+ },
+ time: function(value, arg){
+ // summary: Formats a time according to the given format
+ value = ddfd._toDate(value);
+ if(!value) return "";
+ arg = arg || "P";
+ return dojox.dtl.utils.date.format(value, arg);
+ },
+ timesince: function(value, arg){
+ // summary: Formats a date as the time since that date (i.e. "4 days, 6 hours")
+ value = ddfd._toDate(value);
+ if(!value) return "";
+ var timesince = dojox.dtl.utils.date.timesince;
+ if(arg) return timesince(arg, value);
+ return timesince(value);
+ },
+ timeuntil: function(value, arg){
+ // summary: Formats a date as the time until that date (i.e. "4 days, 6 hours")
+ value = ddfd._toDate(value);
+ if(!value) return "";
+ var timesince = dojox.dtl.utils.date.timesince;
+ if(arg) return timesince(arg, value);
+ return timesince(new Date(), value);
+ }
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/filter/htmlstrings.js b/includes/js/dojox/dtl/filter/htmlstrings.js
new file mode 100644
index 0000000..d4feb93
--- /dev/null
+++ b/includes/js/dojox/dtl/filter/htmlstrings.js
@@ -0,0 +1,59 @@
+if(!dojo._hasResource["dojox.dtl.filter.htmlstrings"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.filter.htmlstrings"] = true;
+dojo.provide("dojox.dtl.filter.htmlstrings");
+
+dojo.require("dojox.dtl._base");
+
+dojo.mixin(dojox.dtl.filter.htmlstrings, {
+ _escapeamp: /&/g,
+ _escapelt: /</g,
+ _escapegt: />/g,
+ _escapeqt: /'/g,
+ _escapedblqt: /"/g,
+ _linebreaksrn: /(\r\n|\n\r)/g,
+ _linebreaksn: /\n{2,}/g,
+ _linebreakss: /(^\s+|\s+$)/g,
+ _linebreaksbr: /\n/g,
+ _removetagsfind: /[a-z0-9]+/g,
+ _striptags: /<[^>]*?>/g,
+ escape: function(value){
+ // summary: Escapes a string's HTML
+ var dh = dojox.dtl.filter.htmlstrings;
+ return value.replace(dh._escapeamp, '&amp;').replace(dh._escapelt, '&lt;').replace(dh._escapegt, '&gt;').replace(dh._escapedblqt, '&quot;').replace(dh._escapeqt, '&#39;');
+ },
+ linebreaks: function(value){
+ // summary: Converts newlines into <p> and <br />s
+ var output = [];
+ var dh = dojox.dtl.filter.htmlstrings;
+ value = value.replace(dh._linebreaksrn, "\n");
+ var parts = value.split(dh._linebreaksn);
+ for(var i = 0; i < parts.length; i++){
+ var part = parts[i].replace(dh._linebreakss, "").replace(dh._linebreaksbr, "<br />")
+ output.push("<p>" + part + "</p>");
+ }
+
+ return output.join("\n\n");
+ },
+ linebreaksbr: function(value){
+ // summary: Converts newlines into <br />s
+ var dh = dojox.dtl.filter.htmlstrings;
+ return value.replace(dh._linebreaksrn, "\n").replace(dh._linebreaksbr, "<br />");
+ },
+ removetags: function(value, arg){
+ // summary: Removes a space separated list of [X]HTML tags from the output"
+ var dh = dojox.dtl.filter.htmlstrings;
+ var tags = [];
+ var group;
+ while(group = dh._removetagsfind.exec(arg)){
+ tags.push(group[0]);
+ }
+ tags = "(" + tags.join("|") + ")";
+ return value.replace(new RegExp("</?\s*" + tags + "\s*[^>]*>", "gi"), "");
+ },
+ striptags: function(value){
+ // summary: Strips all [X]HTML tags
+ return value.replace(dojox.dtl.filter.htmlstrings._striptags, "");
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/filter/integers.js b/includes/js/dojox/dtl/filter/integers.js
new file mode 100644
index 0000000..0c54a90
--- /dev/null
+++ b/includes/js/dojox/dtl/filter/integers.js
@@ -0,0 +1,32 @@
+if(!dojo._hasResource["dojox.dtl.filter.integers"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.filter.integers"] = true;
+dojo.provide("dojox.dtl.filter.integers");
+
+dojo.mixin(dojox.dtl.filter.integers, {
+ add: function(value, arg){
+ value = parseInt(value);
+ arg = parseInt(arg);
+ return isNaN(arg) ? value : value + arg;
+ },
+ get_digit: function(value, arg){
+ // summary:
+ // Given a whole number, returns the 1-based requested digit of it
+ // desciprtion:
+ // 1 is the right-most digit, 2 is the second-right-most digit, etc. Returns the
+ // original value for invalid input (if input or argument is not an integer,
+ // or if argument is less than 1). Otherwise, output is always an integer.
+ value = parseInt(value);
+ arg = parseInt(arg) - 1;
+ if(arg >= 0){
+ value += "";
+ if(arg < value.length){
+ value = parseInt(value.charAt(arg));
+ }else{
+ value = 0;
+ }
+ }
+ return (isNaN(value) ? 0 : value);
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/filter/lists.js b/includes/js/dojox/dtl/filter/lists.js
new file mode 100644
index 0000000..b095242
--- /dev/null
+++ b/includes/js/dojox/dtl/filter/lists.js
@@ -0,0 +1,137 @@
+if(!dojo._hasResource["dojox.dtl.filter.lists"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.filter.lists"] = true;
+dojo.provide("dojox.dtl.filter.lists")
+
+dojo.require("dojox.dtl._base");
+
+dojo.mixin(dojox.dtl.filter.lists, {
+ _dictsort: function(a, b){
+ if(a[0] == b[0]) return 0;
+ return (a[0] < b[0]) ? -1 : 1;
+ },
+ dictsort: function(value, arg){
+ // summary: Takes a list of dicts, returns that list sorted by the property given in the argument.
+ if(!arg) return value;
+
+ var i, item, items = [];
+ if(!dojo.isArray(value)){
+ var obj = value, value = [];
+ for(var key in obj){
+ value.push(obj[k]);
+ }
+ }
+ for(i = 0; i < value.length; i++){
+ items.push([new dojox.dtl._Filter('var.' + arg).resolve(new dojox.dtl._Context({ 'var' : value[i]})), value[i]]);
+ }
+ items.sort(dojox.dtl.filter.lists._dictsort);
+ var output = [];
+ for(i = 0; item = items[i]; i++){
+ output.push(item[1]);
+ }
+ return output;
+ },
+ dictsortreversed: function(value, arg){
+ // summary: Takes a list of dicts, returns that list sorted in reverse order by the property given in the argument.
+ if(!arg) return value;
+
+ var dictsort = dojox.dtl.filter.lists.dictsort(value, arg);
+ return dictsort.reverse();
+ },
+ first: function(value){
+ // summary: Returns the first item in a list
+ return (value.length) ? value[0] : "";
+ },
+ join: function(value, arg){
+ // summary: Joins a list with a string, like Python's ``str.join(list)``
+ // description:
+ // Django throws a compile error, but JS can't do arg checks
+ // so we're left with run time errors, which aren't wise for something
+ // as trivial here as an empty arg.
+ return value.join(arg || ",");
+ },
+ length: function(value){
+ // summary: Returns the length of the value - useful for lists
+ return (isNaN(value.length)) ? (value + "").length : value.length;
+ },
+ length_is: function(value, arg){
+ // summary: Returns a boolean of whether the value's length is the argument
+ return value.length == parseInt(arg);
+ },
+ random: function(value){
+ // summary: Returns a random item from the list
+ return value[Math.floor(Math.random() * value.length)];
+ },
+ slice: function(value, arg){
+ // summary: Returns a slice of the list.
+ // description:
+ // Uses the same syntax as Python's list slicing; see
+ // http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice
+ // for an introduction.
+ // Also uses the optional third value to denote every X item.
+ arg = arg || "";
+ var parts = arg.split(":");
+ var bits = [];
+ for(var i = 0; i < parts.length; i++){
+ if(!parts[i].length){
+ bits.push(null);
+ }else{
+ bits.push(parseInt(parts[i]));
+ }
+ }
+
+ if(bits[0] === null){
+ bits[0] = 0;
+ }
+ if(bits[0] < 0){
+ bits[0] = value.length + bits[0];
+ }
+ if(bits.length < 2 || bits[1] === null){
+ bits[1] = value.length;
+ }
+ if(bits[1] < 0){
+ bits[1] = value.length + bits[1];
+ }
+
+ return value.slice(bits[0], bits[1]);
+ },
+ _unordered_list: function(value, tabs){
+ var ddl = dojox.dtl.filter.lists;
+ var i, indent = "";
+ for(i = 0; i < tabs; i++){
+ indent += "\t";
+ }
+ if(value[1] && value[1].length){
+ var recurse = [];
+ for(i = 0; i < value[1].length; i++){
+ recurse.push(ddl._unordered_list(value[1][i], tabs + 1))
+ }
+ return indent + "<li>" + value[0] + "\n" + indent + "<ul>\n" + recurse.join("\n") + "\n" + indent + "</ul>\n" + indent + "</li>";
+ }else{
+ return indent + "<li>" + value[0] + "</li>";
+ }
+ },
+ unordered_list: function(value){
+ // summary:
+ // Recursively takes a self-nested list and returns an HTML unordered list --
+ // WITHOUT opening and closing <ul> tags.
+ // description:
+ // The list is assumed to be in the proper format. For example, if ``var`` contains
+ // ``['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]]``,
+ // then ``{{ var|unordered_list }}`` would return::
+ //
+ // | <li>States
+ // | <ul>
+ // | <li>Kansas
+ // | <ul>
+ // | <li>Lawrence</li>
+ // | <li>Topeka</li>
+ // | </ul>
+ // | </li>
+ // | <li>Illinois</li>
+ // | </ul>
+ // | </li>
+ return dojox.dtl.filter.lists._unordered_list(value, 1);
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/filter/logic.js b/includes/js/dojox/dtl/filter/logic.js
new file mode 100644
index 0000000..b69a1a8
--- /dev/null
+++ b/includes/js/dojox/dtl/filter/logic.js
@@ -0,0 +1,34 @@
+if(!dojo._hasResource["dojox.dtl.filter.logic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.filter.logic"] = true;
+dojo.provide("dojox.dtl.filter.logic");
+
+dojo.mixin(dojox.dtl.filter.logic, {
+ default_: function(value, arg){
+ // summary: If value is unavailable, use given default
+ return value || arg || "";
+ },
+ default_if_none: function(value, arg){
+ // summary: If value is null, use given default
+ return (value === null) ? arg || "" : value || "";
+ },
+ divisibleby: function(value, arg){
+ // summary: Returns true if the value is devisible by the argument"
+ return (parseInt(value) % parseInt(arg)) == 0;
+ },
+ _yesno: /\s*,\s*/g,
+ yesno: function(value, arg){
+ // summary:
+ // arg being a comma-delimited string, value of true/false/none
+ // chooses the appropriate item from the string
+ if(!arg) arg = 'yes,no,maybe';
+ var parts = arg.split(dojox.dtl.filter.logic._yesno);
+ if(parts.length < 2){
+ return value;
+ }
+ if(value) return parts[0];
+ if((!value && value !== null) || parts.length < 3) return parts[1];
+ return parts[2];
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/filter/misc.js b/includes/js/dojox/dtl/filter/misc.js
new file mode 100644
index 0000000..0704d25
--- /dev/null
+++ b/includes/js/dojox/dtl/filter/misc.js
@@ -0,0 +1,59 @@
+if(!dojo._hasResource["dojox.dtl.filter.misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.filter.misc"] = true;
+dojo.provide("dojox.dtl.filter.misc");
+
+dojo.mixin(dojox.dtl.filter.misc, {
+ filesizeformat: function(value){
+ // summary: Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102bytes, etc).
+ value = parseFloat(value);
+ if(value < 1024){
+ return (value == 1) ? value + " byte" : value + " bytes";
+ }else if(value < 1024 * 1024){
+ return (value / 1024).toFixed(1) + " KB";
+ }else if(value < 1024 * 1024 * 1024){
+ return (value / 1024 / 1024).toFixed(1) + " MB";
+ }
+ return (value / 1024 / 1024 / 1024).toFixed(1) + " GB";
+ },
+ pluralize: function(value, arg){
+ // summary:
+ // Returns a plural suffix if the value is not 1, for '1 vote' vs. '2 votes'
+ // description:
+ // By default, 's' is used as a suffix; if an argument is provided, that string
+ // is used instead. If the provided argument contains a comma, the text before
+ // the comma is used for the singular case.
+ arg = arg || 's';
+ if(arg.indexOf(",") == -1){
+ arg = "," + arg;
+ }
+ var parts = arg.split(",");
+ if(parts.length > 2){
+ return "";
+ }
+ var singular = parts[0];
+ var plural = parts[1];
+
+ if(parseInt(value) != 1){
+ return plural;
+ }
+ return singular;
+ },
+ _phone2numeric: { a: 2, b: 2, c: 2, d: 3, e: 3, f: 3, g: 4, h: 4, i: 4, j: 5, k: 5, l: 5, m: 6, n: 6, o: 6, p: 7, r: 7, s: 7, t: 8, u: 8, v: 8, w: 9, x: 9, y: 9 },
+ phone2numeric: function(value){
+ // summary: Takes a phone number and converts it in to its numerical equivalent
+ var dm = dojox.dtl.filter.misc;
+ value = value + "";
+ var output = "";
+ for(var i = 0; i < value.length; i++){
+ var chr = value.charAt(i).toLowerCase();
+ (dm._phone2numeric[chr]) ? output += dm._phone2numeric[chr] : output += value.charAt(i);
+ }
+ return output;
+ },
+ pprint: function(value){
+ // summary: A wrapper around toJson unless something better comes along
+ return dojo.toJson(value);
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/filter/strings.js b/includes/js/dojox/dtl/filter/strings.js
new file mode 100644
index 0000000..1270574
--- /dev/null
+++ b/includes/js/dojox/dtl/filter/strings.js
@@ -0,0 +1,327 @@
+if(!dojo._hasResource["dojox.dtl.filter.strings"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.filter.strings"] = true;
+dojo.provide("dojox.dtl.filter.strings");
+
+dojo.require("dojox.dtl.filter.htmlstrings");
+dojo.require("dojox.string.sprintf");
+dojo.require("dojox.string.tokenize");
+
+dojo.mixin(dojox.dtl.filter.strings, {
+ _urlquote: function(/*String*/ url, /*String?*/ safe){
+ if(!safe){
+ safe = "/";
+ }
+ return dojox.string.tokenize(url, /([^\w-_.])/g, function(token){
+ if(safe.indexOf(token) == -1){
+ if(token == " "){
+ return "+";
+ }else{
+ return "%" + token.charCodeAt(0).toString(16).toUpperCase();
+ }
+ }
+ return token;
+ }).join("");
+ },
+ addslashes: function(value){
+ // summary: Adds slashes - useful for passing strings to JavaScript, for example.
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/'/g, "\\'");
+ },
+ capfirst: function(value){
+ // summary: Capitalizes the first character of the value
+ value = "" + value;
+ return value.charAt(0).toUpperCase() + value.substring(1);
+ },
+ center: function(value, arg){
+ // summary: Centers the value in a field of a given width
+ arg = arg || value.length;
+ value = value + "";
+ var diff = arg - value.length;
+ if(diff % 2){
+ value = value + " ";
+ diff -= 1;
+ }
+ for(var i = 0; i < diff; i += 2){
+ value = " " + value + " ";
+ }
+ return value;
+ },
+ cut: function(value, arg){
+ // summary: Removes all values of arg from the given string
+ arg = arg + "" || "";
+ value = value + "";
+ return value.replace(new RegExp(arg, "g"), "");
+ },
+ _fix_ampersands: /&(?!(\w+|#\d+);)/g,
+ fix_ampersands: function(value){
+ // summary: Replaces ampersands with ``&amp;`` entities
+ return value.replace(dojox.dtl.filter.strings._fix_ampersands, "&amp;");
+ },
+ floatformat: function(value, arg){
+ // summary: Format a number according to arg
+ // description:
+ // If called without an argument, displays a floating point
+ // number as 34.2 -- but only if there's a point to be displayed.
+ // With a positive numeric argument, it displays that many decimal places
+ // always.
+ // With a negative numeric argument, it will display that many decimal
+ // places -- but only if there's places to be displayed.
+ arg = parseInt(arg || -1);
+ value = parseFloat(value);
+ var m = value - value.toFixed(0);
+ if(!m && arg < 0){
+ return value.toFixed();
+ }
+ value = value.toFixed(Math.abs(arg));
+ return (arg < 0) ? parseFloat(value) + "" : value;
+ },
+ iriencode: function(value){
+ return dojox.dtl.filter.strings._urlquote(value, "/#%[]=:;$&()+,!");
+ },
+ linenumbers: function(value){
+ // summary: Displays text with line numbers
+ var df = dojox.dtl.filter;
+ var lines = value.split("\n");
+ var output = [];
+ var width = (lines.length + "").length;
+ for(var i = 0, line; i < lines.length; i++){
+ line = lines[i];
+ output.push(df.strings.ljust(i + 1, width) + ". " + df.htmlstrings.escape(line));
+ }
+ return output.join("\n");
+ },
+ ljust: function(value, arg){
+ value = value + "";
+ arg = parseInt(arg);
+ while(value.length < arg){
+ value = value + " ";
+ }
+ return value;
+ },
+ lower: function(value){
+ // summary: Converts a string into all lowercase
+ return (value + "").toLowerCase();
+ },
+ make_list: function(value){
+ // summary:
+ // Returns the value turned into a list. For an integer, it's a list of
+ // digits. For a string, it's a list of characters.
+ var output = [];
+ if(typeof value == "number"){
+ value = value + "";
+ }
+ if(value.charAt){
+ for(var i = 0; i < value.length; i++){
+ output.push(value.charAt(i));
+ }
+ return output;
+ }
+ if(typeof value == "object"){
+ for(var key in value){
+ output.push(value[key]);
+ }
+ return output;
+ }
+ return [];
+ },
+ rjust: function(value, arg){
+ value = value + "";
+ arg = parseInt(arg);
+ while(value.length < arg){
+ value = " " + value;
+ }
+ return value;
+ },
+ slugify: function(value){
+ // summary: Converts to lowercase, removes
+ // non-alpha chars and converts spaces to hyphens
+ value = value.replace(/[^\w\s-]/g, "").toLowerCase();
+ return value.replace(/[\-\s]+/g, "-");
+ },
+ _strings: {},
+ stringformat: function(value, arg){
+ // summary:
+ // Formats the variable according to the argument, a string formatting specifier.
+ // This specifier uses Python string formating syntax, with the exception that
+ // the leading "%" is dropped.
+ arg = "" + arg;
+ var strings = dojox.dtl.filter.strings._strings;
+ if(!strings[arg]){
+ strings[arg] = new dojox.string.sprintf.Formatter("%" + arg);
+ }
+ return strings[arg].format(value);
+ },
+ title: function(value){
+ // summary: Converts a string into titlecase
+ var last, title = "";
+ for(var i = 0, current; i < value.length; i++){
+ current = value.charAt(i);
+ if(last == " " || last == "\n" || last == "\t" || !last){
+ title += current.toUpperCase();
+ }else{
+ title += current.toLowerCase();
+ }
+ last = current;
+ }
+ return title;
+ },
+ _truncatewords: /[ \n\r\t]/,
+ truncatewords: function(value, arg){
+ // summary: Truncates a string after a certain number of words
+ // arg: Integer
+ // Number of words to truncate after
+ arg = parseInt(arg);
+ if(!arg){
+ return value;
+ }
+
+ for(var i = 0, j = value.length, count = 0, current, last; i < value.length; i++){
+ current = value.charAt(i);
+ if(dojox.dtl.filter.strings._truncatewords.test(last)){
+ if(!dojox.dtl.filter.strings._truncatewords.test(current)){
+ ++count;
+ if(count == arg){
+ return value.substring(0, j + 1);
+ }
+ }
+ }else if(!dojox.dtl.filter.strings._truncatewords.test(current)){
+ j = i;
+ }
+ last = current;
+ }
+ return value;
+ },
+ _truncate_words: /(&.*?;|<.*?>|(\w[\w\-]*))/g,
+ _truncate_tag: /<(\/)?([^ ]+?)(?: (\/)| .*?)?>/,
+ _truncate_singlets: { br: true, col: true, link: true, base: true, img: true, param: true, area: true, hr: true, input: true },
+ truncatewords_html: function(value, arg){
+ arg = parseInt(arg);
+
+ if(arg <= 0){
+ return "";
+ }
+
+ var strings = dojox.dtl.filter.strings;
+ var words = 0;
+ var open = [];
+
+ var output = dojox.string.tokenize(value, strings._truncate_words, function(all, word){
+ if(word){
+ // It's an actual non-HTML word
+ ++words;
+ if(words < arg){
+ return word;
+ }else if(words == arg){
+ return word + " ...";
+ }
+ }
+ // Check for tag
+ var tag = all.match(strings._truncate_tag);
+ if(!tag || words >= arg){
+ // Don't worry about non tags or tags after our truncate point
+ return;
+ }
+ var closing = tag[1];
+ var tagname = tag[2].toLowerCase();
+ var selfclosing = tag[3];
+ if(closing || strings._truncate_singlets[tagname]){
+ }else if(closing){
+ var i = dojo.indexOf(open, tagname);
+ if(i != -1){
+ open = open.slice(i + 1);
+ }
+ }else{
+ open.unshift(tagname);
+ }
+ return all;
+ }).join("");
+
+ output = output.replace(/\s+$/g, "");
+
+ for(var i = 0, tag; tag = open[i]; i++){
+ output += "</" + tag + ">";
+ }
+
+ return output;
+ },
+ upper: function(value){
+ return value.toUpperCase();
+ },
+ urlencode: function(value){
+ return dojox.dtl.filter.strings._urlquote(value);
+ },
+ _urlize: /^((?:[(>]|&lt;)*)(.*?)((?:[.,)>\n]|&gt;)*)$/,
+ _urlize2: /^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$/,
+ urlize: function(value){
+ return dojox.dtl.filter.strings.urlizetrunc(value);
+ },
+ urlizetrunc: function(value, arg){
+ arg = parseInt(arg);
+ return dojox.string.tokenize(value, /(\S+)/g, function(word){
+ var matches = dojox.dtl.filter.strings._urlize.exec(word);
+ if(!matches){
+ return word;
+ }
+ var lead = matches[1];
+ var middle = matches[2];
+ var trail = matches[3];
+
+ var startsWww = middle.indexOf("www.") == 0;
+ var hasAt = middle.indexOf("@") != -1;
+ var hasColon = middle.indexOf(":") != -1;
+ var startsHttp = middle.indexOf("http://") == 0;
+ var startsHttps = middle.indexOf("https://") == 0;
+ var firstAlpha = /[a-zA-Z0-9]/.test(middle.charAt(0));
+ var last4 = middle.substring(middle.length - 4);
+
+ var trimmed = middle;
+ if(arg > 3){
+ trimmed = trimmed.substring(0, arg - 3) + "...";
+ }
+
+ if(startsWww || (!hasAt && !startsHttp && middle.length && firstAlpha && (last4 == ".org" || last4 == ".net" || last4 == ".com"))){
+ return '<a href="http://' + middle + '" rel="nofollow">' + trimmed + '</a>';
+ }else if(startsHttp || startsHttps){
+ return '<a href="' + middle + '" rel="nofollow">' + trimmed + '</a>';
+ }else if(hasAt && !startsWww && !hasColon && dojox.dtl.filter.strings._urlize2.test(middle)){
+ return '<a href="mailto:' + middle + '">' + middle + '</a>';
+ }
+ return word;
+ }).join("");
+ },
+ wordcount: function(value){
+ return dojox.dtl.text.pySplit(value).length;
+ },
+ wordwrap: function(value, arg){
+ arg = parseInt(arg);
+ // summary: Wraps words at specified line length
+ var output = [];
+ var parts = value.split(/ /g);
+ if(parts.length){
+ var word = parts.shift();
+ output.push(word);
+ var pos = word.length - word.lastIndexOf("\n") - 1;
+ for(var i = 0; i < parts.length; i++){
+ word = parts[i];
+ if(word.indexOf("\n") != -1){
+ var lines = word.split(/\n/g);
+ }else{
+ var lines = [word];
+ }
+ pos += lines[0].length + 1;
+ if(arg && pos > arg){
+ output.push("\n");
+ pos = lines[lines.length - 1].length;
+ }else{
+ output.push(" ");
+ if(lines.length > 1){
+ pos = lines[lines.length - 1].length;
+ }
+ }
+ output.push(word);
+ }
+ }
+ return output.join("");
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/html.js b/includes/js/dojox/dtl/html.js
new file mode 100644
index 0000000..c984157
--- /dev/null
+++ b/includes/js/dojox/dtl/html.js
@@ -0,0 +1,818 @@
+if(!dojo._hasResource["dojox.dtl.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.html"] = true;
+dojo.provide("dojox.dtl.html");
+
+dojo.require("dojox.dtl._base");
+dojo.require("dojox.dtl.Context");
+
+(function(){
+ var dd = dojox.dtl;
+
+ var ddt = dd.text;
+ var ddh = dd.html = {
+ types: dojo.mixin({change: -11, attr: -12, custom: -13, elem: 1, text: 3}, ddt.types),
+ _attributes: {},
+ _re4: /^function anonymous\(\)\s*{\s*(.*)\s*}$/,
+ getTemplate: function(text){
+ if(typeof this._commentable == "undefined"){
+ // Check to see if the browser can handle comments
+ this._commentable = false;
+ var div = document.createElement("div");
+ div.innerHTML = "<!--Test comment handling, and long comments, using comments whenever possible.-->";
+ if(div.childNodes.length && div.childNodes[0].nodeType == 8 && div.childNodes[0].data == "comment"){
+ this._commentable = true;
+ }
+ }
+
+ if(!this._commentable){
+ // Strip comments
+ text = text.replace(/<!--({({|%).*?(%|})})-->/g, "$1");
+ }
+
+ var match;
+ var pairs = [
+ [true, "select", "option"],
+ [dojo.isSafari, "tr", "th"],
+ [dojo.isSafari, "tr", "td"],
+ [dojo.isSafari, "thead", "tr", "th"],
+ [dojo.isSafari, "tbody", "tr", "td"]
+ ];
+ // Some tags can't contain text. So we wrap the text in tags that they can have.
+ for(var i = 0, pair; pair = pairs[i]; i++){
+ if(!pair[0]){
+ continue;
+ }
+ if(text.indexOf("<" + pair[1]) != -1){
+ var selectRe = new RegExp("<" + pair[1] + "[\\s\\S]*?>([\\s\\S]+?)</" + pair[1] + ">", "ig");
+ while(match = selectRe.exec(text)){
+ // Do it like this to make sure we don't double-wrap
+ var found = false;
+ var tokens = dojox.string.tokenize(match[1], new RegExp("(<" + pair[2] + "[\\s\\S]*?>[\\s\\S]*?</" + pair[2] + ">)", "ig"), function(child){ found = true; return {data: child}; });
+ if(found){
+ var replace = [];
+ for(var j = 0; j < tokens.length; j++) {
+ if(dojo.isObject(tokens[j])){
+ replace.push(tokens[j].data);
+ }else{
+ var close = pair[pair.length - 1];
+ var k, replacement = "";
+ for(k = 2; k < pair.length - 1; k++){
+ replacement += "<" + pair[k] + ">";
+ }
+ replacement += "<" + close + ' iscomment="true">' + dojo.trim(tokens[j]) + "</" + close + ">";
+ for(k = 2; k < pair.length - 1; k++){
+ replacement += "</" + pair[k] + ">";
+ }
+ replace.push(replacement);
+ }
+ }
+ text = text.replace(match[1], replace.join(""));
+ }
+ }
+ }
+ }
+
+ var re = /\b([a-zA-Z]+)=['"]/g;
+ while(match = re.exec(text)){
+ this._attributes[match[1].toLowerCase()] = true;
+ }
+ var div = document.createElement("div");
+ div.innerHTML = text;
+ var output = {nodes: []};
+ while(div.childNodes.length){
+ output.nodes.push(div.removeChild(div.childNodes[0]))
+ }
+
+ return output;
+ },
+ tokenize: function(/*Node*/ nodes){
+ var tokens = [];
+
+ for(var i = 0, node; node = nodes[i++];){
+ if(node.nodeType != 1){
+ this.__tokenize(node, tokens);
+ }else{
+ this._tokenize(node, tokens);
+ }
+ }
+
+ return tokens;
+ },
+ _swallowed: [],
+ _tokenize: function(/*Node*/ node, /*Array*/ tokens){
+ var types = this.types;
+ var first = false;
+ var swallowed = this._swallowed;
+ var i, j, tag, child;
+
+ if(!tokens.first){
+ // Try to efficiently associate tags that use an attribute to
+ // remove the node from DOM (eg dojoType) so that we can efficiently
+ // locate them later in the tokenizing.
+ first = tokens.first = true;
+ var tags = dd.register.getAttributeTags();
+ for(i = 0; tag = tags[i]; i++){
+ try{
+ (tag[2])({ swallowNode: function(){ throw 1; }}, "");
+ }catch(e){
+ swallowed.push(tag);
+ }
+ }
+ }
+
+
+ for(i = 0; tag = swallowed[i]; i++){
+ var text = node.getAttribute(tag[0]);
+ if(text){
+ var swallowed = false;
+ var custom = (tag[2])({ swallowNode: function(){ swallowed = true; return node; }}, text);
+ if(swallowed){
+ if(node.parentNode && node.parentNode.removeChild){
+ node.parentNode.removeChild(node);
+ }
+ tokens.push([types.custom, custom]);
+ return;
+ }
+ }
+ }
+
+ var children = [];
+ if(dojo.isIE && node.tagName == "SCRIPT"){
+ children.push({
+ nodeType: 3,
+ data: node.text
+ });
+ node.text = "";
+ }else{
+ for(i = 0; child = node.childNodes[i]; i++){
+ children.push(child);
+ }
+ }
+
+ tokens.push([types.elem, node]);
+
+ var change = false;
+ if(children.length){
+ // Only do a change request if we need to
+ tokens.push([types.change, node]);
+ change = true;
+ }
+
+ for(var key in this._attributes){
+ var value = "";
+ if(key == "class"){
+ value = node.className || value;
+ }else if(key == "for"){
+ value = node.htmlFor || value;
+ }else if(key == "value" && node.value == node.innerHTML){
+ // Sometimes .value is set the same as the contents of the item (button)
+ continue;
+ }else if(node.getAttribute){
+ value = node.getAttribute(key, 2) || value;
+ if(key == "href" || key == "src"){
+ if(dojo.isIE){
+ var hash = location.href.lastIndexOf(location.hash);
+ var href = location.href.substring(0, hash).split("/");
+ href.pop();
+ href = href.join("/") + "/";
+ if(value.indexOf(href) == 0){
+ value = value.replace(href, "");
+ }
+ value = decodeURIComponent(value);
+ }
+ if(value.indexOf("{%") != -1 || value.indexOf("{{") != -1){
+ node.setAttribute(key, "");
+ }
+ }
+ }
+ if(typeof value == "function"){
+ value = value.toString().replace(this._re4, "$1");
+ }
+
+ if(!change){
+ // Only do a change request if we need to
+ tokens.push([types.change, node]);
+ change = true;
+ }
+ // We'll have to resolve attributes during parsing
+ tokens.push([types.attr, node, key, value]);
+ }
+
+ for(i = 0, child; child = children[i]; i++){
+ if(child.nodeType == 1 && child.getAttribute("iscomment")){
+ child.parentNode.removeChild(child);
+ child = {
+ nodeType: 8,
+ data: child.innerHTML
+ };
+ }
+ this.__tokenize(child, tokens);
+ }
+
+ if(!first && node.parentNode && node.parentNode.tagName){
+ if(change){
+ tokens.push([types.change, node, true]);
+ }
+ tokens.push([types.change, node.parentNode]);
+ node.parentNode.removeChild(node);
+ }else{
+ // If this node is parentless, it's a base node, so we have to "up" change to itself
+ // and note that it's a top-level to watch for errors
+ tokens.push([types.change, node, true, true]);
+ }
+ },
+ __tokenize: function(child, tokens){
+ var types = this.types;
+ var data = child.data;
+ switch(child.nodeType){
+ case 1:
+ this._tokenize(child, tokens);
+ return;
+ case 3:
+ if(data.match(/[^\s\n]/) && (data.indexOf("{{") != -1 || data.indexOf("{%") != -1)){
+ var texts = ddt.tokenize(data);
+ for(var j = 0, text; text = texts[j]; j++){
+ if(typeof text == "string"){
+ tokens.push([types.text, text]);
+ }else{
+ tokens.push(text);
+ }
+ }
+ }else{
+ tokens.push([child.nodeType, child]);
+ }
+ if(child.parentNode) child.parentNode.removeChild(child);
+ return;
+ case 8:
+ if(data.indexOf("{%") == 0){
+ var text = dojo.trim(data.slice(2, -2));
+ if(text.substr(0, 5) == "load "){
+ var parts = dd.text.pySplit(dojo.trim(text));
+ for(var i = 1, part; part = parts[i]; i++){
+ dojo["require"](part);
+ }
+ }
+ tokens.push([types.tag, text]);
+ }
+ if(data.indexOf("{{") == 0){
+ tokens.push([types.varr, dojo.trim(data.slice(2, -2))]);
+ }
+ if(child.parentNode) child.parentNode.removeChild(child);
+ return;
+ }
+ }
+ };
+
+ dd.HtmlTemplate = dojo.extend(function(/*String|DOMNode|dojo._Url*/ obj){
+ // summary: Use this object for HTML templating
+ if(!obj.nodes){
+ var node = dojo.byId(obj);
+ if(node){
+ dojo.forEach(["class", "src", "href", "name", "value"], function(item){
+ ddh._attributes[item] = true;
+ });
+ obj = {
+ nodes: [node]
+ };
+ }else{
+ if(typeof obj == "object"){
+ obj = ddt.getTemplateString(obj);
+ }
+ obj = ddh.getTemplate(obj);
+ }
+ }
+
+ var tokens = ddh.tokenize(obj.nodes);
+ if(dd.tests){
+ this.tokens = tokens.slice(0);
+ }
+
+ var parser = new dd._HtmlParser(tokens);
+ this.nodelist = parser.parse();
+ },
+ {
+ _count: 0,
+ _re: /\bdojo:([a-zA-Z0-9_]+)\b/g,
+ setClass: function(str){
+ this.getRootNode().className = str;
+ },
+ getRootNode: function(){
+ return this.rootNode;
+ },
+ getBuffer: function(){
+ return new dd.HtmlBuffer();
+ },
+ render: function(context, buffer){
+ buffer = buffer || this.getBuffer();
+ this.rootNode = null;
+ var output = this.nodelist.render(context || new dd.Context({}), buffer);
+ this.rootNode = buffer.getRootNode();
+ for(var i = 0, node; node = buffer._cache[i]; i++){
+ if(node._cache){
+ node._cache.length = 0;
+ }
+ }
+ return output;
+ },
+ unrender: function(context, buffer){
+ return this.nodelist.unrender(context, buffer);
+ }
+ });
+
+ dd.HtmlBuffer = dojo.extend(function(/*Node*/ parent){
+ // summary: Allows the manipulation of DOM
+ // description:
+ // Use this to append a child, change the parent, or
+ // change the attribute of the current node.
+ this._parent = parent;
+ this._cache = [];
+ },
+ {
+ concat: function(/*DOMNode*/ node){
+ var parent = this._parent;
+ if(node.parentNode && node.parentNode.tagName && parent && !parent._dirty){
+ return this;
+ }
+
+ if(node.nodeType == 1 && !this.rootNode){
+ this.rootNode = node || true;
+ }
+
+ if(!parent){
+ if(node.nodeType == 3 && dojo.trim(node.data)){
+ throw new Error("Text should not exist outside of the root node in template");
+ }
+ return this;
+ }
+ if(this._closed && (node.nodeType != 3 || dojo.trim(node.data))){
+ throw new Error("Content should not exist outside of the root node in template");
+ }
+ if(parent._dirty){
+ if(node._drawn && node.parentNode == parent){
+ var caches = parent._cache;
+ if(caches){
+ for(var i = 0, cache; cache = caches[i]; i++){
+ this.onAddNode(cache);
+ parent.insertBefore(cache, node);
+ this.onAddNodeComplete(cache);
+ }
+ caches.length = 0;
+ }
+ }
+ parent._dirty = false;
+ }
+ if(!parent._cache){
+ parent._cache = [];
+ this._cache.push(parent);
+ }
+ parent._dirty = true;
+ parent._cache.push(node);
+ return this;
+ },
+ remove: function(obj){
+ if(typeof obj == "string"){
+ if(this._parent){
+ this._parent.removeAttribute(obj);
+ }
+ }else{
+ if(obj.nodeType == 1 && !this.getRootNode() && !this._removed){
+ this._removed = true;
+ return this;
+ }
+ if(obj.parentNode){
+ this.onRemoveNode();
+ if(obj.parentNode){
+ obj.parentNode.removeChild(obj);
+ }
+ }
+ }
+ return this;
+ },
+ setAttribute: function(key, value){
+ if(key == "class"){
+ this._parent.className = value;
+ }else if(key == "for"){
+ this._parent.htmlFor = value;
+ }else if(this._parent.setAttribute){
+ this._parent.setAttribute(key, value);
+ }
+ return this;
+ },
+ addEvent: function(context, type, fn, /*Array|Function*/ args){
+ if(!context.getThis()){ throw new Error("You must use Context.setObject(instance)"); }
+ this.onAddEvent(this.getParent(), type, fn);
+ var resolved = fn;
+ if(dojo.isArray(args)){
+ resolved = function(e){
+ this[fn].apply(this, [e].concat(args));
+ }
+ }
+ return dojo.connect(this.getParent(), type, context.getThis(), resolved);
+ },
+ setParent: function(node, /*Boolean?*/ up, /*Boolean?*/ root){
+ if(!this._parent) this._parent = this._first = node;
+
+ if(up && root && node === this._first){
+ this._closed = true;
+ }
+
+ if(up){
+ var parent = this._parent;
+ var script = "";
+ var ie = dojo.isIE && parent.tagName == "SCRIPT";
+ if(ie){
+ parent.text = "";
+ }
+ if(parent._dirty){
+ var caches = parent._cache;
+ for(var i = 0, cache; cache = caches[i]; i++){
+ if(cache !== parent){
+ this.onAddNode(cache);
+ if(ie){
+ script += cache.data;
+ }else{
+ parent.appendChild(cache);
+ }
+ this.onAddNodeComplete(cache);
+ }
+ }
+ caches.length = 0;
+ parent._dirty = false;
+ }
+ if(ie){
+ parent.text = script;
+ }
+ }
+
+ this.onSetParent(node, up);
+ this._parent = node;
+ return this;
+ },
+ getParent: function(){
+ return this._parent;
+ },
+ getRootNode: function(){
+ return this.rootNode;
+ },
+ onSetParent: function(node, up){
+ // summary: Stub called when setParent is used.
+ },
+ onAddNode: function(node){
+ // summary: Stub called before new nodes are added
+ },
+ onAddNodeComplete: function(node){
+ // summary: Stub called after new nodes are added
+ },
+ onRemoveNode: function(node){
+ // summary: Stub called when nodes are removed
+ },
+ onClone: function(/*DOMNode*/ from, /*DOMNode*/ to){
+ // summary: Stub called when a node is duplicated
+ },
+ onAddEvent: function(/*DOMNode*/ node, /*String*/ type, /*String*/ description){
+ // summary: Stub to call when you're adding an event
+ }
+ });
+
+ dd._HtmlNode = dojo.extend(function(node){
+ // summary: Places a node into DOM
+ this.contents = node;
+ },
+ {
+ render: function(context, buffer){
+ this._rendered = true;
+ return buffer.concat(this.contents);
+ },
+ unrender: function(context, buffer){
+ if(!this._rendered){
+ return buffer;
+ }
+ this._rendered = false;
+ return buffer.remove(this.contents);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.contents);
+ }
+ });
+
+ dd._HtmlNodeList = dojo.extend(function(/*Node[]*/ nodes){
+ // summary: A list of any HTML-specific node object
+ // description:
+ // Any object that's used in the constructor or added
+ // through the push function much implement the
+ // render, unrender, and clone functions.
+ this.contents = nodes || [];
+ },
+ {
+ push: function(node){
+ this.contents.push(node);
+ },
+ unshift: function(node){
+ this.contents.unshift(node);
+ },
+ render: function(context, buffer, /*Node*/ instance){
+ buffer = buffer || dd.HtmlTemplate.prototype.getBuffer();
+
+ if(instance){
+ var parent = buffer.getParent();
+ }
+ for(var i = 0; i < this.contents.length; i++){
+ buffer = this.contents[i].render(context, buffer);
+ if(!buffer) throw new Error("Template node render functions must return their buffer");
+ }
+ if(parent){
+ buffer.setParent(parent);
+ }
+ return buffer;
+ },
+ dummyRender: function(context, buffer, asNode){
+ // summary: A really expensive way of checking to see how a rendering will look.
+ // Used in the ifchanged tag
+ var div = document.createElement("div");
+
+ var parent = buffer.getParent();
+ var old = parent._clone;
+ // Tell the clone system to attach itself to our new div
+ parent._clone = div;
+ var nodelist = this.clone(buffer, div);
+ if(old){
+ // Restore state if there was a previous clone
+ parent._clone = old;
+ }else{
+ // Remove if there was no clone
+ parent._clone = null;
+ }
+
+ buffer = dd.HtmlTemplate.prototype.getBuffer();
+ nodelist.unshift(new dd.ChangeNode(div));
+ nodelist.push(new dd.ChangeNode(div, true));
+ nodelist.render(context, buffer);
+
+ if(asNode){
+ return buffer.getRootNode();
+ }
+
+ var html = div.innerHTML;
+ return (dojo.isIE) ? html.replace(/\s*_(dirty|clone)="[^"]*"/g, "") : html;
+ },
+ unrender: function(context, buffer){
+ for(var i = 0; i < this.contents.length; i++){
+ buffer = this.contents[i].unrender(context, buffer);
+ if(!buffer) throw new Error("Template node render functions must return their buffer");
+ }
+ return buffer;
+ },
+ clone: function(buffer){
+ // summary:
+ // Used to create an identical copy of a NodeList, useful for things like the for tag.
+ var parent = buffer.getParent();
+ var contents = this.contents;
+ var nodelist = new dd._HtmlNodeList();
+ var cloned = [];
+ for(var i = 0; i < contents.length; i++){
+ var clone = contents[i].clone(buffer);
+ if(clone instanceof dd.ChangeNode || clone instanceof dd._HtmlNode){
+ var item = clone.contents._clone;
+ if(item){
+ clone.contents = item;
+ }else if(parent != clone.contents && clone instanceof dd._HtmlNode){
+ var node = clone.contents;
+ clone.contents = clone.contents.cloneNode(false);
+ buffer.onClone(node, clone.contents);
+ cloned.push(node);
+ node._clone = clone.contents;
+ }
+ }
+ nodelist.push(clone);
+ }
+
+ for(var i = 0, clone; clone = cloned[i]; i++){
+ clone._clone = null;
+ }
+
+ return nodelist;
+ }
+ });
+
+ dd._HtmlVarNode = dojo.extend(function(str){
+ // summary: A node to be processed as a variable
+ // description:
+ // Will render an object that supports the render function
+ // and the getRootNode function
+ this.contents = new dd._Filter(str);
+ this._lists = {};
+ },
+ {
+ render: function(context, buffer){
+ this._rendered = true;
+
+ var str = this.contents.resolve(context);
+ if(str && str.render && str.getRootNode){
+ var root = this._curr = str.getRootNode();
+ var lists = this._lists;
+ var list = lists[root];
+ if(!list){
+ list = lists[root] = new dd._HtmlNodeList();
+ list.push(new dd.ChangeNode(buffer.getParent()));
+ list.push(new dd._HtmlNode(root));
+ list.push(str);
+ list.push(new dd.ChangeNode(buffer.getParent()));
+ }
+ return list.render(context, buffer);
+ }else{
+ if(!this._txt){
+ this._txt = document.createTextNode(str);
+ }
+ this._txt.data = str;
+ return buffer.concat(this._txt);
+ }
+ },
+ unrender: function(context, buffer){
+ if(!this._rendered){
+ return buffer;
+ }
+ this._rendered = false;
+ if(this._curr){
+ return this._lists[this._curr].unrender(context, buffer);
+ }else if(this._txt){
+ return buffer.remove(this._txt);
+ }
+ return buffer;
+ },
+ clone: function(){
+ return new this.constructor(this.contents.getExpression());
+ }
+ });
+
+ dd.ChangeNode = dojo.extend(function(node, /*Boolean?*/ up, /*Bookean*/ root){
+ // summary: Changes the parent during render/unrender
+ this.contents = node;
+ this.up = up;
+ this.root = root;
+ },
+ {
+ render: function(context, buffer){
+ return buffer.setParent(this.contents, this.up, this.root);
+ },
+ unrender: function(context, buffer){
+ if(!this.contents.parentNode){
+ return buffer;
+ }
+ if(!buffer.getParent()){
+ return buffer;
+ }
+ return buffer.setParent(this.contents);
+ },
+ clone: function(){
+ return new this.constructor(this.contents, this.up, this.root);
+ }
+ });
+
+ dd.AttributeNode = dojo.extend(function(key, value, nodelist){
+ // summary: Works on attributes
+ this.key = key;
+ this.value = value;
+ this.nodelist = nodelist || (new dd.Template(value)).nodelist;
+
+ this.contents = "";
+ },
+ {
+ render: function(context, buffer){
+ var key = this.key;
+ var value = this.nodelist.dummyRender(context);
+ if(this._rendered){
+ if(value != this.contents){
+ this.contents = value;
+ return buffer.setAttribute(key, value);
+ }
+ }else{
+ this._rendered = true;
+ this.contents = value;
+ return buffer.setAttribute(key, value);
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return buffer.remove(this.key);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.key, this.value, this.nodelist.clone(buffer));
+ }
+ });
+
+ dd._HtmlTextNode = dojo.extend(function(str){
+ // summary: Adds a straight text node without any processing
+ this.contents = document.createTextNode(str);
+ },
+ {
+ set: function(data){
+ this.contents.data = data;
+ },
+ render: function(context, buffer){
+ return buffer.concat(this.contents);
+ },
+ unrender: function(context, buffer){
+ return buffer.remove(this.contents);
+ },
+ clone: function(){
+ return new this.constructor(this.contents.data);
+ }
+ });
+
+ dd._HtmlParser = dojo.extend(function(tokens){
+ // summary: Turn a simple array into a set of objects
+ // description:
+ // This is also used by all tags to move through
+ // the list of nodes.
+ this.contents = tokens;
+ },
+ {
+ i: 0,
+ parse: function(/*Array?*/ stop_at){
+ var types = ddh.types;
+ var terminators = {};
+ var tokens = this.contents;
+ if(!stop_at){
+ stop_at = [];
+ }
+ for(var i = 0; i < stop_at.length; i++){
+ terminators[stop_at[i]] = true;
+ }
+ var nodelist = new dd._HtmlNodeList();
+ while(this.i < tokens.length){
+ var token = tokens[this.i++];
+ var type = token[0];
+ var value = token[1];
+ if(type == types.custom){
+ nodelist.push(value);
+ }else if(type == types.change){
+ var changeNode = new dd.ChangeNode(value, token[2], token[3]);
+ value[changeNode.attr] = changeNode;
+ nodelist.push(changeNode);
+ }else if(type == types.attr){
+ var fn = ddt.getTag("attr:" + token[2], true);
+ if(fn && token[3]){
+ nodelist.push(fn(null, token[2] + " " + token[3]));
+ }else if(dojo.isString(token[3]) && (token[3].indexOf("{%") != -1 || token[3].indexOf("{{") != -1)){
+ nodelist.push(new dd.AttributeNode(token[2], token[3]));
+ }
+ }else if(type == types.elem){
+ var fn = ddt.getTag("node:" + value.tagName.toLowerCase(), true);
+ if(fn){
+ // TODO: We need to move this to tokenization so that it's before the
+ // node and the parser can be passed here instead of null
+ nodelist.push(fn(null, value, value.tagName.toLowerCase()));
+ }
+ nodelist.push(new dd._HtmlNode(value));
+ }else if(type == types.varr){
+ nodelist.push(new dd._HtmlVarNode(value));
+ }else if(type == types.text){
+ nodelist.push(new dd._HtmlTextNode(value.data || value));
+ }else if(type == types.tag){
+ if(terminators[value]){
+ --this.i;
+ return nodelist;
+ }
+ var cmd = value.split(/\s+/g);
+ if(cmd.length){
+ cmd = cmd[0];
+ var fn = ddt.getTag(cmd);
+ if(typeof fn != "function"){
+ throw new Error("Function not found for " + cmd);
+ }
+ var tpl = fn(this, value);
+ if(tpl){
+ nodelist.push(tpl);
+ }
+ }
+ }
+ }
+
+ if(stop_at.length){
+ throw new Error("Could not find closing tag(s): " + stop_at.toString());
+ }
+
+ return nodelist;
+ },
+ next: function(){
+ // summary: Used by tags to discover what token was found
+ var token = this.contents[this.i++];
+ return {type: token[0], text: token[1]};
+ },
+ skipPast: function(endtag){
+ return dd.Parser.prototype.skipPast.call(this, endtag);
+ },
+ getVarNodeConstructor: function(){
+ return dd._HtmlVarNode;
+ },
+ getTextNodeConstructor: function(){
+ return dd._HtmlTextNode;
+ },
+ getTemplate: function(/*String*/ loc){
+ return new dd.HtmlTemplate(ddh.getTemplate(loc));
+ }
+ });
+
+})();
+
+}
diff --git a/includes/js/dojox/dtl/render/html.js b/includes/js/dojox/dtl/render/html.js
new file mode 100644
index 0000000..943dfbe
--- /dev/null
+++ b/includes/js/dojox/dtl/render/html.js
@@ -0,0 +1,76 @@
+if(!dojo._hasResource["dojox.dtl.render.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.render.html"] = true;
+dojo.provide("dojox.dtl.render.html");
+dojo.require("dojox.dtl.Context");
+
+dojox.dtl.render.html.sensitivity = {
+ // summary:
+ // Set conditions under which to buffer changes
+ // description:
+ // Necessary if you make a lot of changes to your template.
+ // What happens is that the entire node, from the attached DOM Node
+ // down gets swapped with a clone, and until the entire rendering
+ // is complete, we don't replace the clone again. In this way, renders are
+ // "batched".
+ //
+ // But, if we're only changing a small number of nodes, we might no want to buffer at all.
+ // The higher numbers mean that even small changes will result in buffering.
+ // Each higher level includes the lower levels.
+ NODE: 1, // If a node changes, implement buffering
+ ATTRIBUTE: 2, // If an attribute or node changes, implement buffering
+ TEXT: 3 // If any text at all changes, implement buffering
+}
+dojox.dtl.render.html.Render = function(/*DOMNode?*/ attachPoint, /*dojox.dtl.HtmlTemplate?*/ tpl){
+ this._tpl = tpl;
+ this.domNode = attachPoint;
+ this._swap = dojo.hitch(this, function(){
+ // summary: Swaps the node out the first time the DOM is changed
+ // description: Gets swapped back it at end of render
+ if(this.domNode === this._tpl.getRootNode()){
+ var frag = this.domNode;
+ this.domNode = this.domNode.cloneNode(true);
+ frag.parentNode.replaceChild(this.domNode, frag);
+ }
+ });
+}
+dojo.extend(dojox.dtl.render.html.Render, {
+ sensitivity: dojox.dtl.render.html.sensitivity,
+ setAttachPoint: function(/*Node*/ node){
+ this.domNode = node;
+ },
+ render: function(/*Object*/ context, /*dojox.dtl.HtmlTemplate?*/ tpl, /*dojox.dtl.HtmlBuffer?*/ buffer){
+ if(!this.domNode){
+ throw new Error("You cannot use the Render object without specifying where you want to render it");
+ }
+
+ tpl = tpl || this._tpl;
+ buffer = buffer || tpl.getBuffer();
+ context = context || new dojox.dtl.Context();
+
+ if(context.getThis() && context.getThis().buffer == this.sensitivity.NODE){
+ var onAddNode = dojo.connect(buffer, "onAddNode", this, "_swap");
+ var onRemoveNode = dojo.connect(buffer, "onRemoveNode", this, "_swap");
+ }
+
+ if(this._tpl && this._tpl !== tpl){
+ this._tpl.unrender(context, buffer);
+ }
+ this._tpl = tpl;
+
+ var frag = tpl.render(context, buffer).getParent();
+ if(!frag){
+ throw new Error("Rendered template does not have a root node");
+ }
+
+ dojo.disconnect(onAddNode);
+ dojo.disconnect(onRemoveNode);
+
+ if(this.domNode !== frag){
+ this.domNode.parentNode.replaceChild(frag, this.domNode);
+ dojo._destroyElement(this.domNode);
+ this.domNode = frag;
+ }
+ }
+});
+
+}
diff --git a/includes/js/dojox/dtl/tag/date.js b/includes/js/dojox/dtl/tag/date.js
new file mode 100644
index 0000000..fba4089
--- /dev/null
+++ b/includes/js/dojox/dtl/tag/date.js
@@ -0,0 +1,29 @@
+if(!dojo._hasResource["dojox.dtl.tag.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tag.date"] = true;
+dojo.provide("dojox.dtl.tag.date");
+
+dojo.require("dojox.dtl._base");
+dojo.require("dojox.dtl.utils.date");
+
+dojox.dtl.tag.date.NowNode = function(format, TextNode){
+ this.format = new dojox.dtl.utils.date.DateFormat(format);
+ this.contents = new TextNode("");
+}
+dojo.extend(dojox.dtl.tag.date.NowNode, {
+ render: function(context, buffer){
+ this.contents.set(this.format.format(new Date()));
+ return this.contents.render(context, buffer);
+ }
+});
+
+dojox.dtl.tag.date.now = function(parser, text){
+ // Split by either :" or :'
+ var parts = text.split((text.substring(0, 5) == "now '") ? "'" : '"');
+ if(parts.length != 3){
+ throw new Error("'now' statement takes one argument");
+ }
+ var format = parts[1];
+ return new dojox.dtl.tag.date.NowNode(format, parser.getTextNodeConstructor());
+}
+
+}
diff --git a/includes/js/dojox/dtl/tag/loader.js b/includes/js/dojox/dtl/tag/loader.js
new file mode 100644
index 0000000..36c81bc
--- /dev/null
+++ b/includes/js/dojox/dtl/tag/loader.js
@@ -0,0 +1,277 @@
+if(!dojo._hasResource["dojox.dtl.tag.loader"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tag.loader"] = true;
+dojo.provide("dojox.dtl.tag.loader");
+
+dojo.require("dojox.dtl._base");
+
+(function(){
+ var dd = dojox.dtl;
+ var ddtl = dd.tag.loader;
+
+ ddtl.BlockNode = dojo.extend(function(name, nodelist){
+ this.name = name;
+ this.nodelist = nodelist; // Can be overridden
+ },
+ {
+ render: function(context, buffer){
+ var name = this.name;
+ var nodelist = this.nodelist;
+ if(buffer.blocks){
+ var block = buffer.blocks[name];
+ if(block){
+ nodelist = block.nodelist;
+ block.used = true;
+ }
+ }
+ this.rendered = nodelist;
+ return nodelist.render(context, buffer, this);
+ },
+ unrender: function(context, buffer){
+ return this.rendered.unrender(context, buffer);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.name, this.nodelist.clone(buffer));
+ },
+ setOverride: function(nodelist){
+ // summary: In a shared parent, we override, not overwrite
+ if(!this.override){
+ this.override = nodelist;
+ }
+ },
+ toString: function(){ return "dojox.dtl.tag.loader.BlockNode"; }
+ });
+
+ ddtl.ExtendsNode = dojo.extend(function(getTemplate, nodelist, shared, parent, key){
+ this.getTemplate = getTemplate;
+ this.nodelist = nodelist;
+ this.shared = shared;
+ this.parent = parent;
+ this.key = key;
+ },
+ {
+ parents: {},
+ getParent: function(context){
+ if(!this.parent){
+ this.parent = context.get(this.key, false);
+ if(!this.parent){
+ throw new Error("extends tag used a variable that did not resolve");
+ }
+ if(typeof this.parent == "object"){
+ if(this.parent.url){
+ if(this.parent.shared){
+ this.shared = true;
+ }
+ this.parent = this.parent.url.toString();
+ }else{
+ this.parent = this.parent.toString();
+ }
+ }
+ if(this.parent && this.parent.indexOf("shared:") == 0){
+ this.shared = true;
+ this.parent = this.parent.substring(7, parent.length);
+ }
+ }
+ var parent = this.parent;
+ if(!parent){
+ throw new Error("Invalid template name in 'extends' tag.");
+ }
+ if(parent.render){
+ return parent;
+ }
+ if(this.parents[parent]){
+ return this.parents[parent];
+ }
+ this.parent = this.getTemplate(dojox.dtl.text.getTemplateString(parent));
+ if(this.shared){
+ this.parents[parent] = this.parent;
+ }
+ return this.parent;
+ },
+ render: function(context, buffer){
+ var parent = this.getParent(context);
+
+ buffer.blocks = buffer.blocks || {};
+
+ // The parent won't always be in the default parent's nodelist
+ for(var i = 0, node; node = this.nodelist.contents[i]; i++){
+ if(node instanceof dojox.dtl.tag.loader.BlockNode){
+ buffer.blocks[node.name] = {
+ shared: this.shared,
+ nodelist: node.nodelist,
+ used: false
+ }
+ }
+ }
+
+ this.rendered = parent;
+ buffer = parent.nodelist.render(context, buffer, this);
+
+ var rerender = false;
+ for(var name in buffer.blocks){
+ var block = buffer.blocks[name];
+ if(!block.used){
+ rerender = true;
+ parent.nodelist[0].nodelist.append(block.nodelist);
+ }
+ }
+
+ if(rerender){
+ buffer = parent.nodelist.render(context, buffer, this);
+ }
+
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return this.rendered.unrender(context, buffer, this);
+ },
+ toString: function(){ return "dojox.dtl.block.ExtendsNode"; }
+ });
+
+ ddtl.IncludeNode = dojo.extend(function(path, constant, getTemplate, TextNode, parsed){
+ this._path = path;
+ this.constant = constant;
+ this.path = (constant) ? path : new dd._Filter(path);
+ this.getTemplate = getTemplate;
+ this.TextNode = TextNode;
+ this.parsed = (arguments.length == 5) ? parsed : true;
+ },
+ {
+ _cache: [{}, {}],
+ render: function(context, buffer){
+ var location = ((this.constant) ? this.path : this.path.resolve(context)).toString();
+ var parsed = Number(this.parsed);
+ var dirty = false;
+ if(location != this.last){
+ dirty = true;
+ if(this.last){
+ buffer = this.unrender(context, buffer);
+ }
+ this.last = location;
+ }
+
+ var cache = this._cache[parsed];
+
+ if(parsed){
+ if(!cache[location]){
+ cache[location] = dd.text._resolveTemplateArg(location, true);
+ }
+ if(dirty){
+ var template = this.getTemplate(cache[location]);
+ this.rendered = template.nodelist;
+ }
+ return this.rendered.render(context, buffer, this);
+ }else{
+ if(this.TextNode == dd._TextNode){
+ if(dirty){
+ this.rendered = new this.TextNode("");
+ this.rendered.set(dd.text._resolveTemplateArg(location, true));
+ }
+ return this.rendered.render(context, buffer);
+ }else{
+ if(!cache[location]){
+ var nodelist = [];
+ var div = document.createElement("div");
+ div.innerHTML = dd.text._resolveTemplateArg(location, true);
+ var children = div.childNodes;
+ while(children.length){
+ var removed = div.removeChild(children[0]);
+ nodelist.push(removed);
+ }
+ cache[location] = nodelist;
+ }
+ if(dirty){
+ this.nodelist = [];
+ var exists = true;
+ for(var i = 0, child; child = cache[location][i]; i++){
+ this.nodelist.push(child.cloneNode(true));
+ }
+ }
+ for(var i = 0, node; node = this.nodelist[i]; i++){
+ buffer = buffer.concat(node);
+ }
+ }
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ if(this.rendered){
+ buffer = this.rendered.unrender(context, buffer);
+ }
+ if(this.nodelist){
+ for(var i = 0, node; node = this.nodelist[i]; i++){
+ buffer = buffer.remove(node);
+ }
+ }
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this._path, this.constant, this.getTemplate, this.TextNode, this.parsed);
+ }
+ });
+
+ dojo.mixin(ddtl, {
+ block: function(parser, text){
+ var parts = text.split(" ");
+ var name = parts[1];
+
+ parser._blocks = parser._blocks || {};
+ parser._blocks[name] = parser._blocks[name] || [];
+ parser._blocks[name].push(name);
+
+ var nodelist = parser.parse(["endblock", "endblock " + name]);
+ parser.next();
+ return new dojox.dtl.tag.loader.BlockNode(name, nodelist);
+ },
+ extends_: function(parser, text){
+ var parts = text.split(" ");
+ var shared = false;
+ var parent = null;
+ var key = null;
+ if(parts[1].charAt(0) == '"' || parts[1].charAt(0) == "'"){
+ parent = parts[1].substring(1, parts[1].length - 1);
+ }else{
+ key = parts[1];
+ }
+ if(parent && parent.indexOf("shared:") == 0){
+ shared = true;
+ parent = parent.substring(7, parent.length);
+ }
+ var nodelist = parser.parse();
+ return new dojox.dtl.tag.loader.ExtendsNode(parser.getTemplate, nodelist, shared, parent, key);
+ },
+ include: function(parser, token){
+ var parts = dd.text.pySplit(token);
+ if(parts.length != 2){
+ throw new Error(parts[0] + " tag takes one argument: the name of the template to be included");
+ }
+ var path = parts[1];
+ var constant = false;
+ if((path.charAt(0) == '"' || path.slice(-1) == "'") && path.charAt(0) == path.slice(-1)){
+ path = path.slice(1, -1);
+ constant = true;
+ }
+ return new ddtl.IncludeNode(path, constant, parser.getTemplate, parser.getTextNodeConstructor());
+ },
+ ssi: function(parser, token){
+ // We're going to treat things a little differently here.
+ // First of all, this tag is *not* portable, so I'm not
+ // concerned about it being a "drop in" replacement.
+
+ // Instead, we'll just replicate the include tag, but with that
+ // optional "parsed" parameter.
+ var parts = dd.text.pySplit(token);
+ var parsed = false;
+ if(parts.length == 3){
+ parsed = (parts.pop() == "parsed");
+ if(!parsed){
+ throw new Error("Second (optional) argument to ssi tag must be 'parsed'");
+ }
+ }
+ var node = ddtl.include(parser, parts.join(" "));
+ node.parsed = parsed;
+ return node;
+ }
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/tag/logic.js b/includes/js/dojox/dtl/tag/logic.js
new file mode 100644
index 0000000..90909ce
--- /dev/null
+++ b/includes/js/dojox/dtl/tag/logic.js
@@ -0,0 +1,272 @@
+if(!dojo._hasResource["dojox.dtl.tag.logic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tag.logic"] = true;
+dojo.provide("dojox.dtl.tag.logic");
+
+dojo.require("dojox.dtl._base");
+
+(function(){
+ var dd = dojox.dtl;
+ var ddt = dd.text;
+ var ddtl = dd.tag.logic;
+
+ ddtl.IfNode = dojo.extend(function(bools, trues, falses, type){
+ this.bools = bools;
+ this.trues = trues;
+ this.falses = falses;
+ this.type = type;
+ },
+ {
+ render: function(context, buffer){
+ var i, bool, ifnot, filter, value;
+ if(this.type == "or"){
+ for(i = 0; bool = this.bools[i]; i++){
+ ifnot = bool[0];
+ filter = bool[1];
+ value = filter.resolve(context);
+ if((value && !ifnot) || (ifnot && !value)){
+ if(this.falses){
+ buffer = this.falses.unrender(context, buffer);
+ }
+ return (this.trues) ? this.trues.render(context, buffer, this) : buffer;
+ }
+ }
+ if(this.trues){
+ buffer = this.trues.unrender(context, buffer);
+ }
+ return (this.falses) ? this.falses.render(context, buffer, this) : buffer;
+ }else{
+ for(i = 0; bool = this.bools[i]; i++){
+ ifnot = bool[0];
+ filter = bool[1];
+ value = filter.resolve(context);
+ // If we ever encounter a false value
+ if(value == ifnot){
+ if(this.trues){
+ buffer = this.trues.unrender(context, buffer);
+ }
+ return (this.falses) ? this.falses.render(context, buffer, this) : buffer;
+ }
+ }
+ if(this.falses){
+ buffer = this.falses.unrender(context, buffer);
+ }
+ return (this.trues) ? this.trues.render(context, buffer, this) : buffer;
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ buffer = (this.trues) ? this.trues.unrender(context, buffer) : buffer;
+ buffer = (this.falses) ? this.falses.unrender(context, buffer) : buffer;
+ return buffer;
+ },
+ clone: function(buffer){
+ var trues = (this.trues) ? this.trues.clone(buffer) : null;
+ var falses = (this.falses) ? this.falses.clone(buffer) : null;
+ return new this.constructor(this.bools, trues, falses, this.type);
+ }
+ });
+
+ ddtl.IfEqualNode = dojo.extend(function(var1, var2, trues, falses, negate){
+ this.var1 = new dd._Filter(var1);
+ this.var2 = new dd._Filter(var2);
+ this.trues = trues;
+ this.falses = falses;
+ this.negate = negate;
+ },
+ {
+ render: function(context, buffer){
+ var var1 = this.var1.resolve(context);
+ var var2 = this.var2.resolve(context);
+ if((this.negate && var1 != var2) || (!this.negate && var1 == var2)){
+ if(this.falses){
+ buffer = this.falses.unrender(context, buffer);
+ }
+ return (this.trues) ? this.trues.render(context, buffer, this) : buffer;
+ }
+ if(this.trues){
+ buffer = this.trues.unrender(context, buffer);
+ }
+ return (this.falses) ? this.falses.render(context, buffer, this) : buffer;
+ },
+ unrender: function(context, buffer){
+ return ddtl.IfNode.prototype.unrender.call(this, context, buffer);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.var1.getExpression(), this.var2.getExpression(), this.trues.clone(buffer), this.falses.clone(buffer), this.negate);
+ }
+ });
+
+ ddtl.ForNode = dojo.extend(function(assign, loop, reversed, nodelist){
+ this.assign = assign;
+ this.loop = new dd._Filter(loop);
+ this.reversed = reversed;
+ this.nodelist = nodelist;
+ this.pool = [];
+ },
+ {
+ render: function(context, buffer){
+ var i, j, k;
+ var dirty = false;
+ var assign = this.assign;
+
+ for(k = 0; k < assign.length; k++){
+ if(typeof context[assign[k]] != "undefined"){
+ dirty = true;
+ context.push();
+ break;
+ }
+ }
+
+ var items = this.loop.resolve(context) || [];
+ for(i = items.length; i < this.pool.length; i++){
+ this.pool[i].unrender(context, buffer);
+ }
+ if(this.reversed){
+ items = items.slice(0).reverse();
+ }
+
+ var isObject = dojo.isObject(items) && !dojo.isArrayLike(items);
+ var arred = [];
+ if(isObject){
+ for(var key in items){
+ arred.push(items[key]);
+ }
+ }else{
+ arred = items;
+ }
+
+ var forloop = context.forloop = {
+ parentloop: context.forloop || {}
+ };
+ var j = 0;
+ for(i = 0; i < arred.length; i++){
+ var item = arred[i];
+
+ forloop.counter0 = j;
+ forloop.counter = j + 1;
+ forloop.revcounter0 = arred.length - j - 1;
+ forloop.revcounter = arred.length - j;
+ forloop.first = !j;
+ forloop.last = (j == arred.length - 1);
+
+ if(assign.length > 1 && dojo.isArrayLike(item)){
+ if(!dirty){
+ dirty = true;
+ context.push();
+ }
+ var zipped = {};
+ for(k = 0; k < item.length && k < assign.length; k++){
+ zipped[assign[k]] = item[k];
+ }
+ context.update(zipped);
+ }else{
+ context[assign[0]] = item;
+ }
+
+ if(j + 1 > this.pool.length){
+ this.pool.push(this.nodelist.clone(buffer));
+ }
+ buffer = this.pool[j].render(context, buffer, this);
+ ++j;
+ }
+
+ delete context.forloop;
+ for(k = 0; k < assign.length; k++){
+ delete context[assign[k]];
+ }
+ if(dirty){
+ context.pop();
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ for(var i = 0, pool; pool = this.pool[i]; i++){
+ buffer = pool.unrender(context, buffer);
+ }
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this.assign, this.loop.getExpression(), this.reversed, this.nodelist.clone(buffer));
+ }
+ });
+
+ dojo.mixin(ddtl, {
+ if_: function(parser, text){
+ var i, part, type, bools = [], parts = ddt.pySplit(text);
+ parts.shift();
+ text = parts.join(" ");
+ parts = text.split(" and ");
+ if(parts.length == 1){
+ type = "or";
+ parts = text.split(" or ");
+ }else{
+ type = "and";
+ for(i = 0; i < parts.length; i++){
+ if(parts[i].indexOf(" or ") != -1){
+ // Note, since we split by and, this is the only place we need to error check
+ throw new Error("'if' tags can't mix 'and' and 'or'");
+ }
+ }
+ }
+ for(i = 0; part = parts[i]; i++){
+ var not = false;
+ if(part.indexOf("not ") == 0){
+ part = part.slice(4);
+ not = true;
+ }
+ bools.push([not, new dd._Filter(part)]);
+ }
+ var trues = parser.parse(["else", "endif"]);
+ var falses = false;
+ var token = parser.next();
+ if(token.text == "else"){
+ falses = parser.parse(["endif"]);
+ parser.next();
+ }
+ return new ddtl.IfNode(bools, trues, falses, type);
+ },
+ _ifequal: function(parser, text, negate){
+ var parts = ddt.pySplit(text);
+ if(parts.length != 3){
+ throw new Error(parts[0] + " takes two arguments");
+ }
+ var end = 'end' + parts[0];
+ var trues = parser.parse(["else", end]);
+ var falses = false;
+ var token = parser.next();
+ if(token.text == "else"){
+ falses = parser.parse([end]);
+ parser.next();
+ }
+ return new ddtl.IfEqualNode(parts[1], parts[2], trues, falses, negate);
+ },
+ ifequal: function(parser, text){
+ return ddtl._ifequal(parser, text);
+ },
+ ifnotequal: function(parser, text){
+ return ddtl._ifequal(parser, text, true);
+ },
+ for_: function(parser, text){
+ var parts = ddt.pySplit(text);
+ if(parts.length < 4){
+ throw new Error("'for' statements should have at least four words: " + text);
+ }
+ var reversed = parts[parts.length - 1] == "reversed";
+ var index = (reversed) ? -3 : -2;
+ if(parts[parts.length + index] != "in"){
+ throw new Error("'for' tag received an invalid argument: " + text);
+ }
+ var loopvars = parts.slice(1, index).join(" ").split(/ *, */);
+ for(var i = 0; i < loopvars.length; i++){
+ if(!loopvars[i] || loopvars[i].indexOf(" ") != -1){
+ throw new Error("'for' tag received an invalid argument: " + text);
+ }
+ }
+ var nodelist = parser.parse(["endfor"]);
+ parser.next();
+ return new ddtl.ForNode(loopvars, parts[parts.length + index + 1], reversed, nodelist);
+ }
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/tag/loop.js b/includes/js/dojox/dtl/tag/loop.js
new file mode 100644
index 0000000..3626c52
--- /dev/null
+++ b/includes/js/dojox/dtl/tag/loop.js
@@ -0,0 +1,196 @@
+if(!dojo._hasResource["dojox.dtl.tag.loop"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tag.loop"] = true;
+dojo.provide("dojox.dtl.tag.loop");
+
+dojo.require("dojox.dtl._base");
+dojo.require("dojox.string.tokenize");
+
+(function(){
+ var dd = dojox.dtl;
+ var ddtl = dd.tag.loop;
+
+ ddtl.CycleNode = dojo.extend(function(cyclevars, name, TextNode, shared){
+ this.cyclevars = cyclevars;
+ this.name = name;
+ this.TextNode = TextNode;
+ this.shared = shared || {counter: -1, map: {}};
+ },
+ {
+ render: function(context, buffer){
+ if(context.forloop && !context.forloop.counter0){
+ this.shared.counter = -1;
+ }
+
+ ++this.shared.counter;
+ var value = this.cyclevars[this.shared.counter % this.cyclevars.length];
+
+ var map = this.shared.map;
+ if(!map[value]){
+ map[value] = new dd._Filter(value);
+ }
+ value = map[value].resolve(context, buffer);
+
+ if(this.name){
+ context[this.name] = value;
+ }
+ if(!this.contents){
+ this.contents = new this.TextNode("");
+ }
+ this.contents.set(value);
+ return this.contents.render(context, buffer);
+ },
+ unrender: function(context, buffer){
+ return this.contents.unrender(context, buffer);
+ },
+ clone: function(){
+ return new this.constructor(this.cyclevars, this.name, this.TextNode, this.shared);
+ }
+ });
+
+ ddtl.IfChangedNode = dojo.extend(function(nodes, vars, shared){
+ this.nodes = nodes;
+ this._vars = vars;
+ this.shared = shared || {last: null};
+ this.vars = dojo.map(vars, function(item){
+ return new dojox.dtl._Filter(item);
+ });
+ }, {
+ render: function(context, buffer){
+ if(context.forloop && context.forloop.first){
+ this.shared.last = null;
+ }
+
+ var change;
+ if(this.vars.length){
+ change = dojo.toJson(dojo.map(this.vars, function(item){
+ return item.resolve(context);
+ }));
+ }else{
+ change = this.nodes.dummyRender(context, buffer);
+ }
+
+ if(change != this.shared.last){
+ var firstloop = (this.shared.last === null);
+ this.shared.last = change;
+ context.push();
+ context.ifchanged = {firstloop: firstloop}
+ buffer = this.nodes.render(context, buffer);
+ context.pop();
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ this.nodes.unrender(context, buffer);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.nodes.clone(buffer), this._vars, this.shared);
+ }
+ });
+
+ ddtl.RegroupNode = dojo.extend(function(expression, key, alias){
+ this._expression = expression;
+ this.expression = new dd._Filter(expression);
+ this.key = key;
+ this.alias = alias;
+ },
+ {
+ _push: function(container, grouper, stack){
+ if(stack.length){
+ container.push({ grouper: grouper, list: stack })
+ }
+ },
+ render: function(context, buffer){
+ context[this.alias] = [];
+ var list = this.expression.resolve(context);
+ if(list){
+ var last = null;
+ var stack = [];
+ for(var i = 0; i < list.length; i++){
+ var id = list[i][this.key];
+ if(last !== id){
+ this._push(context[this.alias], last, stack);
+ last = id;
+ stack = [list[i]];
+ }else{
+ stack.push(list[i]);
+ }
+ }
+ this._push(context[this.alias], last, stack);
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return buffer;
+ },
+ clone: function(context, buffer){
+ return this;
+ }
+ });
+
+ dojo.mixin(ddtl, {
+ cycle: function(parser, text){
+ // summary: Cycle among the given strings each time this tag is encountered
+ var args = text.split(" ");
+
+ if(args.length < 2){
+ throw new Error("'cycle' tag requires at least two arguments");
+ }
+
+ if(args[1].indexOf(",") != -1){
+ var vars = args[1].split(",");
+ args = [args[0]];
+ for(var i = 0; i < vars.length; i++){
+ args.push('"' + vars[i] + '"');
+ }
+ }
+
+ if(args.length == 2){
+ var name = args[args.length - 1];
+
+ if(!parser._namedCycleNodes){
+ throw new Error("No named cycles in template: '" + name + "' is not defined");
+ }
+ if(!parser._namedCycleNodes[name]){
+ throw new Error("Named cycle '" + name + "' does not exist");
+ }
+
+ return parser._namedCycleNodes[name];
+ }
+
+ if(args.length > 4 && args[args.length - 2] == "as"){
+ var name = args[args.length - 1];
+
+ var node = new ddtl.CycleNode(args.slice(1, args.length - 2), name, parser.getTextNodeConstructor());
+
+ if(!parser._namedCycleNodes){
+ parser._namedCycleNodes = {};
+ }
+ parser._namedCycleNodes[name] = node;
+ }else{
+ node = new ddtl.CycleNode(args.slice(1), null, parser.getTextNodeConstructor());
+ }
+
+ return node;
+ },
+ ifchanged: function(parser, text){
+ var parts = dojox.dtl.text.pySplit(text);
+ var nodes = parser.parse(["endifchanged"]);
+ parser.next();
+ return new ddtl.IfChangedNode(nodes, parts.slice(1));
+ },
+ regroup: function(parser, text){
+ var tokens = dojox.string.tokenize(dojo.trim(text), /(\s+)/g, function(spaces){
+ return spaces;
+ });
+ if(tokens.length < 11 || tokens[tokens.length - 3] != "as" || tokens[tokens.length - 7] != "by"){
+ throw new Error("Expected the format: regroup list by key as newList");
+ }
+ var expression = tokens.slice(2, -8).join("");
+ var key = tokens[tokens.length - 5];
+ var alias = tokens[tokens.length - 1];
+ return new ddtl.RegroupNode(expression, key, alias);
+ }
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/tag/misc.js b/includes/js/dojox/dtl/tag/misc.js
new file mode 100644
index 0000000..31610d7
--- /dev/null
+++ b/includes/js/dojox/dtl/tag/misc.js
@@ -0,0 +1,291 @@
+if(!dojo._hasResource["dojox.dtl.tag.misc"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tag.misc"] = true;
+dojo.provide("dojox.dtl.tag.misc");
+dojo.require("dojox.dtl._base");
+
+(function(){
+ var dd = dojox.dtl;
+ var ddtm = dd.tag.misc;
+
+ ddtm.DebugNode = dojo.extend(function(TextNode){
+ this._TextNode = TextNode;
+ },
+ {
+ render: function(context, buffer){
+ var keys = context.getKeys();
+ var debug = "";
+ for(var i = 0, key; key = keys[i]; i++){
+ console.debug("DEBUG", key, ":", context[key]);
+ debug += key + ": " + dojo.toJson(context[key]) + "\n\n";
+ }
+ return new this._TextNode(debug).render(context, buffer, this);
+ },
+ unrender: function(context, buffer){
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this._TextNode);
+ },
+ toString: function(){ return "ddtm.DebugNode"; }
+ });
+
+ ddtm.FilterNode = dojo.extend(function(varnode, nodelist){
+ this._varnode = varnode;
+ this._nodelist = nodelist;
+ },
+ {
+ render: function(context, buffer){
+ // Doing this in HTML requires a different buffer with a fake root node
+ var output = this._nodelist.render(context, new dojox.string.Builder());
+ context.update({ "var": output.toString() });
+ var filtered = this._varnode.render(context, buffer);
+ context.pop();
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this._expression, this._nodelist.clone(buffer));
+ }
+ });
+
+ ddtm.FirstOfNode = dojo.extend(function(vars, TextNode){
+ this._vars = vars;
+ this.vars = dojo.map(vars, function(item){
+ return new dojox.dtl._Filter(item);
+ });
+ this.contents = new TextNode("");
+ },
+ {
+ render: function(context, buffer){
+ for(var i = 0, item; item = this.vars[i]; i++){
+ var resolved = item.resolve(context);
+ if(typeof resolved != "undefined"){
+ if(resolved === null){
+ resolved = "null";
+ }
+ this.contents.set(resolved);
+ return this.contents.render(context, buffer);
+ }
+ }
+ return this.contents.unrender(context, buffer);
+ },
+ unrender: function(context, buffer){
+ return this.contents.unrender(context, buffer);
+ },
+ clone: function(buffer){
+ return new this.constructor(this._vars, this.contents.constructor);
+ }
+ });
+
+ ddtm.SpacelessNode = dojo.extend(function(nodelist, TextNode){
+ this.nodelist = nodelist;
+ this.TextNode = TextNode;
+ },
+ {
+ render: function(context, buffer){
+ if(buffer.onAddNodeComplete){
+ // Unfortunately, we have to branch here
+ var watch = [
+ dojo.connect(buffer, "onAddNodeComplete", this, "_watch"),
+ dojo.connect(buffer, "onSetParent", this, "_watchParent")
+ ];
+ buffer = this.nodelist.render(context, buffer);
+ dojo.disconnect(watch[0]);
+ dojo.disconnect(watch[1]);
+ }else{
+ if(!this.contents){
+ this.contents = new this.TextNode("");
+ }
+ var value = this.nodelist.dummyRender(context);
+ this.contents.set(value.replace(/>\s+</g, '><'));
+ buffer = this.contents.render(context, buffer);
+ }
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return this.nodelist.unrender(context, buffer);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.nodelist.clone(buffer));
+ },
+ _isEmpty: function(node){
+ return (node.nodeType == 3 && !node.data.match(/[^\s\n]/));
+ },
+ _watch: function(node){
+ if(this._isEmpty(node)){
+ var remove = false;
+ if(node.parentNode.firstChild == node){
+ node.parentNode.removeChild(node);
+ }
+ }else{
+ var children = node.parentNode.childNodes;
+ if(node.nodeType == 1 && children.length > 2){
+ for(var i = 2, child; child = children[i]; i++){
+ if(children[i - 2].nodeType == 1 && this._isEmpty(children[i - 1])){
+ node.parentNode.removeChild(children[i - 1]);
+ return;
+ }
+ }
+ }
+ }
+ },
+ _watchParent: function(node){
+ var children = node.childNodes;
+ if(children.length){
+ while(node.childNodes.length){
+ var last = node.childNodes[node.childNodes.length - 1];
+ if(!this._isEmpty(last)){
+ return;
+ }
+ node.removeChild(last);
+ }
+ }
+ }
+ });
+
+ ddtm.TemplateTagNode = dojo.extend(function(tag, TextNode){
+ this.tag = tag;
+ this.contents = new TextNode("");
+ },
+ {
+ mapping: {
+ openblock: "{%",
+ closeblock: "%}",
+ openvariable: "{{",
+ closevariable: "}}",
+ openbrace: "{",
+ closebrace: "}",
+ opencomment: "{#",
+ closecomment: "#}"
+ },
+ render: function(context, buffer){
+ this.contents.set(this.mapping[this.tag]);
+ return this.contents.render(context, buffer);
+ },
+ unrender: function(context, buffer){
+ return this.contents.unrender(context, buffer);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.tag, this.contents.constructor);
+ }
+ });
+
+ ddtm.WidthRatioNode = dojo.extend(function(current, max, width, TextNode){
+ this.current = new dd._Filter(current);
+ this.max = new dd._Filter(max);
+ this.width = width;
+ this.contents = new TextNode("");
+ },
+ {
+ render: function(context, buffer){
+ var current = +this.current.resolve(context);
+ var max = +this.max.resolve(context);
+ if(typeof current != "number" || typeof max != "number" || !max){
+ this.contents.set("");
+ }else{
+ this.contents.set("" + Math.round((current / max) * this.width));
+ }
+ return this.contents.render(context, buffer);
+ },
+ unrender: function(context, buffer){
+ return this.contents.unrender(context, buffer);
+ },
+ clone: function(buffer){
+ return new this.constructor(this.current.getExpression(), this.max.getExpression(), this.width, this.contents.constructor);
+ }
+ });
+
+ ddtm.WithNode = dojo.extend(function(target, alias, nodelist){
+ this.target = new dd._Filter(target);
+ this.alias = alias;
+ this.nodelist = nodelist;
+ },
+ {
+ render: function(context, buffer){
+ var target = this.target.resolve(context);
+ context.push();
+ context[this.alias] = target;
+ buffer = this.nodelist.render(context, buffer);
+ context.pop();
+ return buffer;
+ },
+ unrender: function(context, buffer){
+ return buffer;
+ },
+ clone: function(buffer){
+ return new this.constructor(this.target.getExpression(), this.alias, this.nodelist.clone(buffer));
+ }
+ });
+
+ dojo.mixin(ddtm, {
+ comment: function(parser, text){
+ // summary: Ignore everything between {% comment %} and {% endcomment %}
+ parser.skipPast("endcomment");
+ return dd._noOpNode;
+ },
+ debug: function(parser, text){
+ // summary: Output the current context, maybe add more stuff later.
+ return new ddtm.DebugNode(parser.getTextNodeConstructor());
+ },
+ filter: function(parser, text){
+ // summary: Filter the contents of the blog through variable filters.
+ var parts = text.split(" ", 2);
+ var varnode = new (parser.getVarNodeConstructor())("var|" + parts[1]);
+ var nodelist = parser.parse(["endfilter"]);
+ parser.next();
+ return new ddtm.FilterNode(varnode, nodelist);
+ },
+ firstof: function(parser, text){
+ var parts = dojox.dtl.text.pySplit(text).slice(1);
+ if(!parts.length){
+ throw new Error("'firstof' statement requires at least one argument");
+ }
+ return new ddtm.FirstOfNode(parts, parser.getTextNodeConstructor());
+ },
+ spaceless: function(parser, text){
+ var nodelist = parser.parse(["endspaceless"]);
+ parser.next();
+ return new ddtm.SpacelessNode(nodelist, parser.getTextNodeConstructor());
+ },
+ templatetag: function(parser, text){
+ var parts = dd.text.pySplit(text);
+ if(parts.length != 2){
+ throw new Error("'templatetag' statement takes one argument");
+ }
+ var tag = parts[1];
+ var mapping = ddtm.TemplateTagNode.prototype.mapping;
+ if(!mapping[tag]){
+ var keys = [];
+ for(var key in mapping){
+ keys.push(key);
+ }
+ throw new Error("Invalid templatetag argument: '" + tag + "'. Must be one of: " + keys.join(", "));
+ }
+ return new ddtm.TemplateTagNode(tag, parser.getTextNodeConstructor());
+ },
+ widthratio: function(parser, text){
+ var parts = dd.text.pySplit(text);
+ if(parts.length != 4){
+ throw new Error("widthratio takes three arguments");
+ }
+ var width = +parts[3];
+ if(typeof width != "number"){
+ throw new Error("widthratio final argument must be an integer");
+ }
+ return new ddtm.WidthRatioNode(parts[1], parts[2], width, parser.getTextNodeConstructor());
+ },
+ with_: function(parser, text){
+ var parts = dd.text.pySplit(text);
+ if(parts.length != 4 || parts[2] != "as"){
+ throw new Error("do_width expected format as 'with value as name'");
+ }
+ var nodelist = parser.parse(["endwith"]);
+ parser.next();
+ return new ddtm.WithNode(parts[1], parts[3], nodelist);
+ }
+ });
+})();
+
+}
diff --git a/includes/js/dojox/dtl/tests/context.js b/includes/js/dojox/dtl/tests/context.js
new file mode 100644
index 0000000..a366098
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/context.js
@@ -0,0 +1,79 @@
+if(!dojo._hasResource["dojox.dtl.tests.context"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.context"] = true;
+dojo.provide("dojox.dtl.tests.context");
+
+dojo.require("dojox.dtl");
+dojo.require("dojox.dtl.Context");
+
+doh.register("dojox.dtl.context",
+ [
+ function test_context_creation(t){
+ var context = new dojox.dtl.Context({ foo: "foo", bar: "bar" });
+ t.is("foo", context.foo);
+ t.is("bar", context.bar);
+ },
+ function test_context_push(t){
+ var context = new dojox.dtl.Context({ foo: "foo", bar: "bar" });
+ context.push();
+ for(var key in context._dicts[0]){
+ t.t(key == "foo" || key == "bar");
+ }
+ },
+ function test_context_pop(t){
+ var context = new dojox.dtl.Context({ foo: "foo", bar: "bar" });
+ context.push();
+ t.is("undefined", typeof context.foo);
+ t.is("undefined", typeof context.bar);
+ context.pop();
+ t.is("foo", context.foo);
+ t.is("bar", context.bar);
+ },
+ function test_context_overpop(t){
+ var context = new dojox.dtl.Context();
+ try{
+ context.pop();
+ t.t(false);
+ }catch(e){
+ t.is("pop() called on empty Context", e.message);
+ }
+ },
+ function test_context_filter(t){
+ var context = new dojox.dtl.Context({ foo: "one", bar: "two", baz: "three" });
+ var filtered = context.filter("foo", "bar");
+ t.is(filtered.foo, "one");
+ t.is(filtered.bar, "two");
+ t.f(filtered.baz);
+
+ filtered = context.filter({ bar: true, baz: true });
+ t.f(filtered.foo);
+ t.is(filtered.bar, "two");
+ t.is(filtered.baz, "three");
+
+ filtered = context.filter(new dojox.dtl.Context({ foo: true, baz: true }));
+ t.is(filtered.foo, "one");
+ t.f(filtered.bar);
+ t.is(filtered.baz, "three");
+ },
+ function test_context_extend(t){
+ var context = new dojox.dtl.Context({ foo: "one" });
+ var extended = context.extend({ bar: "two", baz: "three" });
+ t.is(extended.foo, "one");
+ t.is(extended.bar, "two");
+ t.is(extended.baz, "three");
+
+ extended = context.extend({ barr: "two", bazz: "three" });
+ t.is(extended.foo, "one");
+ t.f(extended.bar);
+ t.f(extended.baz);
+ t.is(extended.barr, "two");
+ t.is(extended.bazz, "three");
+
+ t.f(context.bar)
+ t.f(context.baz);
+ t.f(context.barr);
+ t.f(context.bazz);
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html b/includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html
new file mode 100644
index 0000000..29e5470
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/demo_Templated_Jaxer.html
@@ -0,0 +1,87 @@
+<html>
+ <head>
+ <title>Demo using dojox.dtl._Templated</title>
+ <script runat="server">
+ djConfig = {baseUrl:"/dojo/",usePlainJson: true, parseOnLoad: true};
+ </script>
+ <script runat="server" type="text/javascript" src="../../../dojo/dojo.js"></script>
+ <script runat="server" type="text/javascript">
+ dojo.require("dojo.jaxer");
+ dojo.require("dijit.dijit");
+ dojo.require("dojox.dtl._Templated");
+ dojo.require("dojo.parser");
+
+ dojo.declare("Fruit", [dijit._Widget, dojox.dtl._Templated], {
+ oldRepl: "Fruit: ",
+ _dijitTemplateCompat: true,
+ items: ["apple", "banana", "orange"],
+ keyUp: function(e){
+ if(e.keyCode == dojo.keys.ENTER){
+ var i = dojo.indexOf(this.items, e.target.value);
+ if(i != -1){
+ this.items.splice(i, 1);
+ }else{
+ this.items.push(e.target.value);
+ }
+ e.target.value = "";
+ this.render();
+ dojo.query("input", this.domNode).forEach("item.focus();");
+ }
+ },
+ templateString: '<div><input dojoAttachEvent="onkeyup: keyUp"><ul>{% for item in items %}<li>${oldRepl} {{ item }}</li>{% endfor %}</ul></div>'
+ });
+ </script>
+ <body>
+ <h1>Using Dojo's Django Template language on Jaxer</h1>
+ <p>
+ Aptana's Jaxer is server side JavaScript (SSJS) server. With some modifications to
+ a web page, Dojo can be run on the server. With Dojo running on the server, you can
+ utilize the Dojo's Django Template library rendering engine to do templating within
+ Jaxer. The latest build of Dojo includes some patches to properly work with Jaxer,
+ so you need a build of Dojo later than 2/18/08 to work with Jaxer. Next, the
+ following modifications to your page are needed to run Jaxer:
+ <ul>
+ <li>
+ You must explicitly set the base url of the Dojo library. Jaxer does not provide
+ the ability for Dojo to auto-detect the base url as it can in other environments.
+ Therefore you must declare the base url with the djConfig global variable:
+ <pre>
+ &lt;script runat="server">
+ djConfig = {baseUrl:"/dojo/", // use the base path of dojo here
+ usePlainJson: true, parseOnLoad: true};
+ &lt;/script>
+ </pre>
+ </li>
+ <li>
+ Next, you must add the runat attribute with a value of "server" to all of the script
+ tags that you want executed on the server. Your script tags should look like:
+ <pre>
+ &lt;script runat="server" type="text/javascript" src="../../../dojo/dojo.js">&lt;/script>
+ </pre>
+ </li>
+ <li>
+ Last, you must dojo.require("dojo.jaxer") with a script tag. This should immediately
+ follow the declaration of dojo.js:
+ <pre>
+ &lt;script runat="server" type="text/javascript" src="../../../dojo/dojo.js">&lt;/script>
+ &lt;script runat="server" type="text/javascript">dojo.require("dojo.jaxer");&lt;/script>
+ </pre>
+ </li>
+ </ul>
+ </p>
+ <p>
+ Once this is done, Dojo should load in Jaxer, and you can utilize the library capabilities of
+ Dojo. In particular, you can now use DTL renderer as you would on
+ the browser. If you are running this in Jaxer, below should be a working demonstration of
+ a template that is rendered on the server.
+ </p>
+ <div dojoType="Fruit"></div>
+ <p>
+ It is important to note that Jaxer is not capable of transferring the programmaticaly set
+ event handlers for widgets, it can only send the static HTML to the browser. This means
+ you can use DTL as a templating engine to create HTML on the server, but Dojo client side widgets
+ are still necessary if you want to use interactive widgets on the browser.
+ </p>
+ </body>
+ </head>
+</html> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/tests/html/buffer.js b/includes/js/dojox/dtl/tests/html/buffer.js
new file mode 100644
index 0000000..3077d8c
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/html/buffer.js
@@ -0,0 +1,35 @@
+if(!dojo._hasResource["dojox.dtl.tests.html.buffer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.html.buffer"] = true;
+dojo.provide("dojox.dtl.tests.html.buffer");
+
+dojo.require("dojox.dtl.html");
+dojo.require("dojox.dtl.Context");
+dojo.require("dojox.dtl.tests.html.util");
+
+doh.register("dojox.dtl.html.buffer",
+ [
+ function test_insertion_order_text(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ first: false,
+ last: false
+ });
+
+ var template = new dd.HtmlTemplate("<div>{% if first %}first{% endif %}middle{% if last %}last{% endif %}</div>");
+ t.is("<div>middle</div>", dd.tests.html.util.render(template, context));
+
+ context.first = true;
+ t.is("<div>firstmiddle</div>", dd.tests.html.util.render(template, context));
+
+ context.first = false;
+ context.last = true;
+ t.is("<div>middlelast</div>", dd.tests.html.util.render(template, context));
+
+ context.first = true;
+ t.is("<div>firstmiddlelast</div>", dd.tests.html.util.render(template, context));
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/dtl/tests/html/tag.js b/includes/js/dojox/dtl/tests/html/tag.js
new file mode 100644
index 0000000..c964913
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/html/tag.js
@@ -0,0 +1,233 @@
+if(!dojo._hasResource["dojox.dtl.tests.html.tag"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.html.tag"] = true;
+dojo.provide("dojox.dtl.tests.html.tag");
+
+dojo.require("dojox.dtl.html");
+dojo.require("dojox.dtl.Context");
+dojo.require("dojox.dtl.tests.html.util");
+
+doh.register("dojox.dtl.html.tag",
+ [
+ function test_errors(t){
+ var dd = dojox.dtl;
+ var template;
+
+ // No root node after rendering
+ var found = false;
+ try {
+ template = new dd.HtmlTemplate('No div');
+ dd.tests.html.util.render(template);
+ }catch(e){
+ t.is("Text should not exist outside of the root node in template", e.message);
+ found = true;
+ }
+ t.t(found);
+
+ var context = new dojox.dtl.Context({test: "Pocket"});
+ found = false;
+ try {
+ template = new dd.HtmlTemplate('{{ test }}');
+ dd.tests.html.util.render(template, context);
+ }catch(e){
+ t.is("Text should not exist outside of the root node in template", e.message);
+ found = true;
+ }
+ t.t(found);
+
+ template = new dd.HtmlTemplate('<div></div>extra content');
+ found = false;
+ try {
+ dd.tests.html.util.render(template);
+ }catch(e){
+ t.is("Content should not exist outside of the root node in template", e.message);
+ found = true;
+ }
+ t.t(found);
+
+ // More than one top-level node (except for blocks)
+ template = new dd.HtmlTemplate('<div></div><div></div>');
+ found = false;
+ try {
+ dd.tests.html.util.render(template);
+ }catch(e){
+ t.is("Content should not exist outside of the root node in template", e.message);
+ found = true;
+ }
+ t.t(found);
+
+ // Logic block rules out any root node
+ template = new dd.HtmlTemplate('{% if missing %}<div></div>{% endif %}');
+ found = false;
+ try {
+ dd.tests.html.util.render(template);
+ }catch(e){
+ t.is("Rendered template does not have a root node", e.message);
+ found = true;
+ }
+ t.t(found);
+ },
+ function test_structures(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ actions: ["ate", "picked"],
+ items: [
+ {
+ name: "apple"
+ },
+ {
+ name: "banana",
+ date: new Date(2007, 2, 16, 14, 30, 10)
+ },
+ {
+ name: "orange",
+ date: new Date(2008, 0, 1, 12, 0, 0)
+ }
+ ]
+ });
+
+ var template = new dd.HtmlTemplate('<div><ul>I {% for action in actions %}{% if not forloop.first %}, {% endif %}{{action}}{% endfor %} the following:<ul>{% for item in items %}<li>{{ item.name }}{% if item.date %} at {{ item.date|date:"P" }}{% endif %}</li>{% endfor %}</ul></ul></div>');
+ t.is('<div><ul>I ate, picked the following:<ul><li>apple</li><li>banana at 2:30 pm</li><li>orange at noon</li></ul></ul></div>', dd.tests.html.util.render(template, context));
+ },
+ function test_tag_extend(t){
+ // Problems to look for:
+ // * Content outside of blocks
+ },
+ function test_tag_for(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ items: ["apple", "banana", "lemon"]
+ });
+ var template = new dd.HtmlTemplate('<div><ul>{% for item in items %}<li class="{{ item|length }}">{{ item }}</li>{% endfor %}</ul></div>');
+
+ t.is('<div><ul><li class="5">apple</li><li class="6">banana</li><li class="5">lemon</li></ul></div>', dd.tests.html.util.render(template, context));
+
+ // The line break is there to make sure our regex works
+ template = new dd.HtmlTemplate('<div><select>{% for item in items %}<option>{{ item }}</option>\n{% endfor %}</select></div>');
+
+ t.is('<div><select><option>apple</option><option>banana</option><option>lemon</option></select></div>', dd.tests.html.util.render(template, context));
+ },
+ function test_tag_if(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({key: true});
+ var template = new dd.HtmlTemplate('{% if key %}<div>has key</div>{% else %}<div>no key</div>{% endif %}');
+ t.is("<div>has key</div>", dd.tests.html.util.render(template, context));
+ context.key = false;
+ t.is("<div>no key</div>", dd.tests.html.util.render(template, context));
+ },
+ function test_tag_ifchanged(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ year: 2008,
+ days: [
+ new Date(2008, 0, 12),
+ new Date(2008, 0, 28),
+ new Date(2008, 1, 1),
+ new Date(2008, 1, 1),
+ new Date(2008, 1, 1)
+ ]
+ });
+
+ var template = new dd.HtmlTemplate("<div><h1>Archive for {{ year }}</h1>"+
+"{% for date in days %}"+
+'{% ifchanged %}<h3>Month: </h3><h3>{{ date|date:"F" }}</h3>{% endifchanged %}'+
+'<a href="{{ date|date:\'M/d\'|lower }}/">{{ date|date:\'j\' }}</a>'+
+"{% endfor %}</div>");
+
+ t.is('<div><h1>Archive for 2008</h1>'+
+'<h3>Month: </h3><h3>January</h3>'+
+'<a href="jan/12/">12</a>'+
+'<a href="jan/28/">28</a>'+
+'<h3>Month: </h3><h3>February</h3>'+
+'<a href="feb/01/">1</a>'+
+'<a href="feb/01/">1</a>'+
+'<a href="feb/01/">1</a></div>', dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate('<div>{% for date in days %}'+
+'{% ifchanged date.date %} {{ date.date }} {% endifchanged %}'+
+'{% ifchanged date.hour date.date %}'+
+'{{ date.hour }}'+
+'{% endifchanged %}'+
+'{% endfor %}</div>');
+ t.is('<div> 2008-01-12 0 2008-01-28 0 2008-02-01 0</div>', dd.tests.html.util.render(template, context));
+ },
+ function test_tag_ifequal(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ items: [
+ { name: "apple", color: "red" },
+ { name: "banana", color: "yellow" },
+ { name: "pear", color: "green" },
+ { name: "kiwi", color: "brown" }
+ ],
+ edit_item: "banana"
+ });
+
+ var template = new dd.HtmlTemplate("<div><ul>{% for item in items %}<li>{{ item.name }}</li>{% endfor %}</ul></div>");
+ t.is('<div><ul><li>apple</li><li>banana</li><li>pear</li><li>kiwi</li></ul></div>', dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate("<div><ul>{% for item in items %}<li><span>{{ item.name }}</span><br/><p>{{ item.color }}</p></li>{% endfor %}</ul></div>");
+ t.is('<div><ul><li><span>apple</span><br/><p>red</p></li><li><span>banana</span><br/><p>yellow</p></li><li><span>pear</span><br/><p>green</p></li><li><span>kiwi</span><br/><p>brown</p></li></ul></div>', dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate("<div><ul>{% for item in items %}<li>{% ifequal item.name edit_item %}<label>Name: <input type='text' name='name' value=\"{{ item.name }}\"/></label><br/><label>Color: <textarea name='color'>{{ item.color }}</textarea></label>{% else %}<span>{{ item.name }}</span><br/><p>{{ item.color }}</p>{% endifequal %}</li>{% endfor %}</ul></div>");
+ t.is('<div><ul><li><span>apple</span><br/><p>red</p></li><li><label>Name: <input type="text" name="name" value="banana"/></label><br/><label>Color: <textarea name="color">yellow</textarea></label></li><li><span>pear</span><br/><p>green</p></li><li><span>kiwi</span><br/><p>brown</p></li></ul></div>', dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate("<div><ul>{% for item in items %}<li>{% ifequal item.name edit_item %}<div><label>Name: <input type='text' name='name' value=\"{{ item.name }}\"/></label><br/><label>Color: <textarea name='color'>{{ item.color }}</textarea></label></div>{% else %}<div><span>{{ item.name }}</span><br/><p>{{ item.color }}</p></div>{% endifequal %}</li>{% endfor %}</ul></div>");
+ t.is('<div><ul><li><div><span>apple</span><br/><p>red</p></div></li><li><div><label>Name: <input type="text" name="name" value="banana"/></label><br/><label>Color: <textarea name="color">yellow</textarea></label></div></li><li><div><span>pear</span><br/><p>green</p></div></li><li><div><span>kiwi</span><br/><p>brown</p></div></li></ul></div>', dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate("<div><ul>{% for item in items %}{% ifequal item.name edit_item %}<li><label>Name: <input type='text' name='name' value=\"{{ item.name }}\"/></label><br/><label>Color: <textarea name='color'>{{ item.color }}</textarea></label></li>{% else %}<li><span>{{ item.name }}</span><br/><p>{{ item.color }}</p></li>{% endifequal %}{% endfor %}</ul></div>");
+ t.is('<div><ul><li><span>apple</span><br/><p>red</p></li><li><label>Name: <input type="text" name="name" value="banana"/></label><br/><label>Color: <textarea name="color">yellow</textarea></label></li><li><span>pear</span><br/><p>green</p></li><li><span>kiwi</span><br/><p>brown</p></li></ul></div>', dd.tests.html.util.render(template, context));
+ },
+ function test_tag_include(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"),
+ person: "Bob",
+ people: ["Charles", "Ralph", "Julia"]
+ });
+
+ var template = new dd.HtmlTemplate("<div>{% include hello %}</div>");
+ t.is("<div>Hello, <span>Bob</span></div>", dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate('<div>{% include "../../dojox/dtl/tests/templates/hello.html" %}</div>');
+ t.is("<div>Hello, <span>Bob</span></div>", dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate('<div>{% for person in people %}<div class="include">{% include hello %} </div>{% endfor %}</div>');
+ t.is('<div><div class="include">Hello, <span>Charles</span> </div><div class="include">Hello, <span>Ralph</span> </div><div class="include">Hello, <span>Julia</span> </div></div>', dd.tests.html.util.render(template, context));
+ },
+ function test_tag_spaceless(t){
+ var dd = dojox.dtl;
+
+ var template = new dd.HtmlTemplate("{% spaceless %}<ul> \n <li>Hot</li> \n\n<li>Pocket </li>\n </ul>{% endspaceless %}");
+ t.is("<ul><li>Hot</li><li>Pocket </li></ul>", dd.tests.html.util.render(template));
+ },
+ function test_tag_ssi(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"),
+ person: "Bob",
+ people: ["Charles", "Ralph", "Julia"]
+ });
+
+ var template = new dd.HtmlTemplate("<div>{% ssi hello parsed %}</div>");
+ t.is("<div>Hello, <span>Bob</span></div>", dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate("<div>{% ssi hello %}</div>");
+ t.is("<div>Hello, <span>{{ person }}</span></div>", dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate('<div>{% ssi "../../dojox/dtl/tests/templates/hello.html" parsed %}</div>');
+ t.is("<div>Hello, <span>Bob</span></div>", dd.tests.html.util.render(template, context));
+
+ template = new dd.HtmlTemplate('<div>{% for person in people %}{% ssi hello parsed %} {% endfor %}</div>');
+ t.is("<div>Hello, <span>Charles</span> Hello, <span>Ralph</span> Hello, <span>Julia</span> </div>", dd.tests.html.util.render(template, context));
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/dtl/tests/html/util.js b/includes/js/dojox/dtl/tests/html/util.js
new file mode 100644
index 0000000..b4efe5a
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/html/util.js
@@ -0,0 +1,160 @@
+if(!dojo._hasResource["dojox.dtl.tests.html.util"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.html.util"] = true;
+dojo.provide("dojox.dtl.tests.html.util");
+
+dojo.require("dojox.dtl.html");
+dojo.require("dojox.dtl.render.html");
+dojo.require("dojox.string.Builder");
+
+dojox.dtl.HtmlBuffer.prototype.onClone = function(from, to){
+ var clones = this._clones = this._clones || [];
+
+ for(var i = 0, group; group = clones[i]; i++){
+ for(var j = 0, item; item = group[j]; j++){
+ if(item === from){
+ group.push(to);
+ return
+ }else if(item === to){
+ group.push(from);
+ return;
+ }
+ }
+ }
+
+ clones.push([from, to]);
+}
+dojox.dtl.HtmlBuffer.prototype.onAddEvent = function(node, type, description){
+ var events = this._events = this._events || [];
+
+ var found = false;
+ for(var i = 0, evt; evt = events[i]; i++){
+ if(evt[0] === node){
+ found = true;
+ evt[1] = type;
+ evt[2] = description;
+ }
+ }
+
+ if(!found){
+ events.push([node, type, description]);
+ }
+}
+
+dojox.dtl.tests.html.util.render = function(/*HtmlTemplate*/ template, /*Context*/ context) {
+ try {
+ var div = document.createElement("div");
+ dojo.style(div, "visibility", "hidden");
+ var attach = document.createElement("div");
+ div.appendChild(attach);
+ dojo.body().appendChild(div);
+
+ var buffer = template.getBuffer();
+ var canvas = new dojox.dtl.render.html.Render(attach, template);
+ canvas.render(context, template, buffer);
+ var clones = buffer._clones;
+ var events = buffer._events;
+
+ var first = dojox.dtl.tests.html.util.serialize(canvas.domNode, template.tokens, clones, events).toString();
+
+ buffer = template.getBuffer();
+ buffer._clones = clones;
+ buffer._events = events;
+ canvas.render(context, template, buffer);
+
+ var second = dojox.dtl.tests.html.util.serialize(canvas.domNode, template.tokens, clones, events).toString();
+
+ doh.is("Compare re-render: " + first, "Compare re-render: " + second);
+ return first;
+ }
+ catch(e){
+ throw e;
+ }finally{
+ div.parentNode.removeChild(div);
+ }
+}
+
+dojox.dtl.tests.html.util.serialize = function(node, tokens, clones, events, output) {
+ var types = dojox.dtl.html.types;
+ clones = clones || [];
+ events = events || [];
+
+ if (node.nodeType == 3) {
+ output.append(node.nodeValue);
+ }else{
+ var name = node.nodeName.toLowerCase();
+
+ if (!output) {
+ output = new dojox.string.Builder();
+ }
+ output.append("<").append(name);
+
+ var attributes = dojo.filter(tokens, function(token){
+ if(token[0] == types.attr){
+ for(var i = 0, group; group = clones[i]; i++){
+ // group is any set of nodes that were originally the sam
+ var count = 0;
+ for(var j = 0, item; item = group[j]; j++){
+ if(item === token[1] || item === node){
+ if(count++){
+ // This is entered when we have 2 hits within a clone group.
+ // The first would be the original node
+ // The second would be if our current node is a clone
+ // of the original
+ return true;
+ }
+ }
+ }
+ }
+ }
+ });
+
+ for(var i = 0, attribute; attribute = attributes[i]; i++){
+ var value = "";
+ if(attribute[2] == "class"){
+ value = node.className || value;
+ }else if(attribute[2] == "for"){
+ value = node.htmlFor || value;
+ }else if(node.getAttribute){
+ value = node.getAttribute(attribute[2], 2) || value;
+ if(dojo.isIE && (attribute[2] == "href" || attribute[2] == "src")){
+ if(dojo.isIE){
+ var hash = location.href.lastIndexOf(location.hash);
+ var href = location.href.substring(0, hash).split("/");
+ href.pop();
+ href = href.join("/") + "/";
+ if(value.indexOf(href) == 0){
+ value = value.replace(href, "");
+ }
+ value = decodeURIComponent(value);
+ }
+ }
+ }
+ if(value){
+ output.append(" ").append(attribute[2]).append('="').append(value.replace(/"/g, '\\"')).append('"');
+ }
+ }
+
+ // Deal with events
+ if(events){
+ for(var i = 0, evt; evt = events[i]; i++){
+ if(evt[0] === node){
+ output.append(" ").append(evt[1]).append('="').append(evt[2]).append('"');
+ }
+ }
+ }
+
+ if(!node.childNodes.length){
+ output.append("/>");
+ }else{
+ output.append(">");
+ dojo.forEach(node.childNodes, function(node){
+ dojox.dtl.tests.html.util.serialize(node, tokens, clones, events, output);
+ });
+ output.append("</").append(name).append(">");
+ }
+
+ return output;
+ }
+}
+
+}
diff --git a/includes/js/dojox/dtl/tests/module.js b/includes/js/dojox/dtl/tests/module.js
new file mode 100644
index 0000000..57dcafb
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/module.js
@@ -0,0 +1,15 @@
+if(!dojo._hasResource["dojox.dtl.tests.module"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.module"] = true;
+dojo.provide("dojox.dtl.tests.module");
+
+try{
+ dojo.require("dojox.dtl.tests.text.filter");
+ dojo.require("dojox.dtl.tests.text.tag");
+ dojo.require("dojox.dtl.tests.html.tag");
+ dojo.require("dojox.dtl.tests.html.buffer");
+ dojo.require("dojox.dtl.tests.context");
+}catch(e){
+ doh.debug(e);
+}
+
+}
diff --git a/includes/js/dojox/dtl/tests/runTests.html b/includes/js/dojox/dtl/tests/runTests.html
new file mode 100644
index 0000000..32338f6
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/runTests.html
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+ <head>
+ <title>Dojox Djanto Template Language D.O.H. Unit Test Runner</title>
+ <meta http-equiv="REFRESH" content="0;url=../../../util/doh/runner.html?testModule=dojox.dtl.tests.module"></HEAD>
+ <BODY>
+ Redirecting to D.O.H runner.
+ </BODY>
+</HTML> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/tests/templates/hello.html b/includes/js/dojox/dtl/tests/templates/hello.html
new file mode 100644
index 0000000..18e4c1a
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/templates/hello.html
@@ -0,0 +1 @@
+Hello, <span>{{ person }}</span> \ No newline at end of file
diff --git a/includes/js/dojox/dtl/tests/templates/pocket.html b/includes/js/dojox/dtl/tests/templates/pocket.html
new file mode 100644
index 0000000..f78c520
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/templates/pocket.html
@@ -0,0 +1 @@
+{% block pocket %}Hot{% endblock %} Pocket \ No newline at end of file
diff --git a/includes/js/dojox/dtl/tests/templates/pocket2.html b/includes/js/dojox/dtl/tests/templates/pocket2.html
new file mode 100644
index 0000000..547f9a2
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/templates/pocket2.html
@@ -0,0 +1 @@
+{% for item in items %}({% block pocket %}Hot{% endblock %}) {% endfor %}Pocket \ No newline at end of file
diff --git a/includes/js/dojox/dtl/tests/text/filter.js b/includes/js/dojox/dtl/tests/text/filter.js
new file mode 100644
index 0000000..d96f931
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/text/filter.js
@@ -0,0 +1,740 @@
+if(!dojo._hasResource["dojox.dtl.tests.text.filter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.text.filter"] = true;
+dojo.provide("dojox.dtl.tests.text.filter");
+
+dojo.require("dojox.dtl");
+dojo.require("dojox.dtl.Context");
+dojo.require("dojox.dtl.utils.date");
+dojo.require("dojox.date.php");
+dojo.require("dojox.string.sprintf");
+
+// If you update something here, update it in the HTML tests
+doh.register("dojox.dtl.text.filter",
+ [
+ function test_filter_add(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ four: 4 });
+ tpl = new dd.Template('{{ four|add:"6" }}');
+ t.is("10", tpl.render(context));
+ context.four = "4";
+ t.is("10", tpl.render(context));
+ tpl = new dd.Template('{{ four|add:"six" }}');
+ t.is("4", tpl.render(context));
+ tpl = new dd.Template('{{ four|add:"6.6" }}');
+ t.is("10", tpl.render(context));
+ },
+ function test_filter_addslashes(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ unslashed: "Test back slashes \\, double quotes \" and single quotes '" })
+ var tpl = new dd.Template('{{ unslashed|addslashes }}');
+ t.is("Test back slashes \\\\, double quotes \\\" and single quotes \\'", tpl.render(context));
+ },
+ function test_filter_capfirst(t){
+ var dd = dojox.dtl;
+
+ var tpl = new dd.Template('{{ uncapped|capfirst }}');
+ t.is("Cap", tpl.render(new dd.Context({ uncapped: "cap" })));
+ },
+ function test_filter_center(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context();
+ var tpl = new dd.Template('{{ narrow|center }}');
+ context.narrow = "even";
+ t.is("even", tpl.render(context));
+ context.narrow = "odd";
+ t.is("odd", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|center:"5" }}');
+ context.narrow = "even";
+ t.is("even ", tpl.render(context));
+ context.narrow = "odd";
+ t.is(" odd ", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|center:"6" }}');
+ context.narrow = "even";
+ t.is(" even ", tpl.render(context));
+ context.narrow = "odd";
+ t.is(" odd ", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|center:"12" }}');
+ context.narrow = "even";
+ t.is(" even ", tpl.render(context));
+ context.narrow = "odd";
+ t.is(" odd ", tpl.render(context));
+ },
+ function test_filter_cut(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ uncut: "Apples and oranges" });
+ var tpl = new dd.Template('{{ uncut|cut }}');
+ t.is("Apples and oranges", tpl.render(context));
+ tpl = new dd.Template('{{ uncut|cut:"A" }}');
+ t.is("pples and oranges", tpl.render(context));
+ tpl = new dd.Template('{{ uncut|cut:" " }}');
+ t.is("Applesandoranges", tpl.render(context));
+ tpl = new dd.Template('{{ uncut|cut:"e" }}');
+ t.is("Appls and orangs", tpl.render(context));
+ },
+ function test_filter_date(t){
+ var dd = dojox.dtl;
+ var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) });
+
+ var tpl = new dd.Template('{{ now|date }}');
+ t.is(dojox.dtl.utils.date.format(context.now, "N j, Y"), tpl.render(context));
+
+ context.then = new Date(2007, 0, 1);
+ tpl = new dd.Template('{{ now|date:"d" }}');
+ t.is("01", tpl.render(context));
+
+ tpl = new dd.Template('{{ now|date:"D" }}');
+ t.is("Mon", tpl.render(context));
+
+ tpl = new dd.Template('{{ now|date:"j" }}');
+ t.is("1", tpl.render(context));
+
+ tpl = new dd.Template('{{ now|date:"l" }}');
+ t.is("Monday", tpl.render(context));
+
+ tpl = new dd.Template('{{ now|date:"N" }}');
+ t.is("Jan.", tpl.render(context));
+
+ tpl = new dd.Template('{{ now|date:"S" }}');
+ t.is("st", tpl.render(context));
+ context.now.setDate(2);
+ t.is("nd", tpl.render(context));
+ context.now.setDate(3);
+ t.is("rd", tpl.render(context));
+ context.now.setDate(4);
+ t.is("th", tpl.render(context));
+ context.now.setDate(5);
+ t.is("th", tpl.render(context));
+ context.now.setDate(6);
+ t.is("th", tpl.render(context));
+ context.now.setDate(7);
+ t.is("th", tpl.render(context));
+ context.now.setDate(8);
+ t.is("th", tpl.render(context));
+ context.now.setDate(9);
+ t.is("th", tpl.render(context));
+ context.now.setDate(10);
+ t.is("th", tpl.render(context));
+ context.now.setDate(11);
+ t.is("th", tpl.render(context));
+ context.now.setDate(12);
+ t.is("th", tpl.render(context));
+ context.now.setDate(13);
+ t.is("th", tpl.render(context));
+ context.now.setDate(14);
+ t.is("th", tpl.render(context));
+ context.now.setDate(15);
+ t.is("th", tpl.render(context));
+ context.now.setDate(16);
+ t.is("th", tpl.render(context));
+ context.now.setDate(17);
+ t.is("th", tpl.render(context));
+ context.now.setDate(18);
+ t.is("th", tpl.render(context));
+ context.now.setDate(19);
+ t.is("th", tpl.render(context));
+ context.now.setDate(20);
+ t.is("th", tpl.render(context));
+ context.now.setDate(21);
+ t.is("st", tpl.render(context));
+ context.now.setDate(22);
+ t.is("nd", tpl.render(context));
+ context.now.setDate(23);
+ t.is("rd", tpl.render(context));
+ context.now.setDate(24);
+ t.is("th", tpl.render(context));
+ context.now.setDate(25);
+ t.is("th", tpl.render(context));
+ context.now.setDate(26);
+ t.is("th", tpl.render(context));
+ context.now.setDate(27);
+ t.is("th", tpl.render(context));
+ context.now.setDate(28);
+ t.is("th", tpl.render(context));
+ context.now.setDate(29);
+ t.is("th", tpl.render(context));
+ context.now.setDate(30);
+ t.is("th", tpl.render(context));
+ context.now.setDate(31);
+ t.is("st", tpl.render(context));
+ context.now.setDate(1);
+
+ tpl = new dd.Template('{{ now|date:"w" }}');
+ t.is("1", tpl.render(context));
+
+ tpl = new dd.Template('{{ now|date:"z" }}');
+ t.is("0", tpl.render(context));
+
+ tpl = new dd.Template('{{ now|date:"W" }}');
+ t.is("1", tpl.render(context));
+ },
+ function test_filter_default(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context();
+ tpl = new dd.Template('{{ empty|default }}');
+ t.is("", tpl.render(context));
+ tpl = new dd.Template('{{ empty|default:"full" }}');
+ t.is("full", tpl.render(context));
+ context.empty = "not empty";
+ t.is("not empty", tpl.render(context));
+ },
+ function test_filter_default_if_none(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context();
+ tpl = new dd.Template('{{ empty|default_if_none }}');
+ t.is("", tpl.render(context));
+ tpl = new dd.Template('{{ empty|default_if_none:"full" }}');
+ t.is("", tpl.render(context));
+ context.empty = null;
+ t.is("full", tpl.render(context));
+ context.empty = "not empty";
+ t.is("not empty", tpl.render(context));
+ },
+ function test_filter_dictsort(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ fruit: [
+ { name: "lemons", toString: function(){ return this.name; } },
+ { name: "apples", toString: function(){ return this.name; } },
+ { name: "grapes", toString: function(){ return this.name; } }
+ ]
+ });
+ tpl = new dd.Template('{{ fruit|dictsort|join:"|" }}');
+ t.is("lemons|apples|grapes", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|dictsort:"name"|join:"|" }}');
+ t.is("apples|grapes|lemons", tpl.render(context));
+ },
+ function test_filter_dictsort_reversed(t){
+ var dd = dojox.dtl;
+
+ context = new dd.Context({
+ fruit: [
+ { name: "lemons", toString: function(){ return this.name; } },
+ { name: "apples", toString: function(){ return this.name; } },
+ { name: "grapes", toString: function(){ return this.name; } }
+ ]
+ });
+ tpl = new dd.Template('{{ fruit|dictsortreversed:"name"|join:"|" }}');
+ t.is("lemons|grapes|apples", tpl.render(context));
+ },
+ function test_filter_divisibleby(t){
+ var dd = dojox.dtl;
+
+ context = new dd.Context();
+ tpl = new dd.Template('{{ 4|divisibleby:"2" }}');
+ t.is("true", tpl.render(context));
+ context = new dd.Context({ number: 4 });
+ tpl = new dd.Template('{{ number|divisibleby:3 }}');
+ t.is("false", tpl.render(context));
+ },
+ function test_filter_escape(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ unescaped: "Try & cover <all> the \"major\" 'situations' at once" });
+ tpl = new dd.Template('{{ unescaped|escape }}');
+ t.is("Try &amp; cover &lt;all&gt; the &quot;major&quot; &#39;situations&#39; at once", tpl.render(context));
+ },
+ function test_filter_filesizeformat(t){
+ var dd = dojox.dtl;
+
+ var tpl = new dd.Template('{{ 1|filesizeformat }}');
+ t.is("1 byte", tpl.render());
+ tpl = new dd.Template('{{ 512|filesizeformat }}');
+ t.is("512 bytes", tpl.render());
+ tpl = new dd.Template('{{ 1024|filesizeformat }}');
+ t.is("1.0 KB", tpl.render());
+ tpl = new dd.Template('{{ 2048|filesizeformat }}');
+ t.is("2.0 KB", tpl.render());
+ tpl = new dd.Template('{{ 1048576|filesizeformat }}');
+ t.is("1.0 MB", tpl.render());
+ tpl = new dd.Template('{{ 1073741824|filesizeformat }}');
+ t.is("1.0 GB", tpl.render());
+ },
+ function test_filter_first(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ fruit: [
+ { name: "lemons", toString: function(){ return this.name; } },
+ { name: "apples", toString: function(){ return this.name; } },
+ { name: "grapes", toString: function(){ return this.name; } }
+ ]
+ });
+ tpl = new dd.Template('{{ fruit|first }}');
+ t.is("lemons", tpl.render(context));
+ },
+ function test_filter_fix_ampersands(t){
+ var dd = dojox.dtl;
+
+ var tpl = new dd.Template('{{ "One & Two"|fix_ampersands }}');
+ t.is("One &amp; Two", tpl.render());
+ },
+ function test_filter_floatformat(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ num1: 34.23234, num2: 34.00000 });
+ var tpl = new dd.Template('{{ num1|floatformat }}');
+ t.is("34.2", tpl.render(context));
+ tpl = new dd.Template('{{ num2|floatformat }}');
+ t.is("34", tpl.render(context));
+ tpl = new dd.Template('{{ num1|floatformat:3 }}');
+ t.is("34.232", tpl.render(context));
+ tpl = new dd.Template('{{ num2|floatformat:3 }}');
+ t.is("34.000", tpl.render(context));
+ tpl = new dd.Template('{{ num1|floatformat:-3 }}');
+ t.is("34.2", tpl.render(context));
+ tpl = new dd.Template('{{ num2|floatformat:-3 }}');
+ t.is("34", tpl.render(context));
+ },
+ function test_filter_get_digit(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ pi: 314159265 });
+ var tpl = new dd.Template('{{ pi|get_digit:1 }}');
+ t.is("3", tpl.render(context));
+ tpl = new dd.Template('{{ pi|get_digit:"2" }}');
+ t.is("1", tpl.render(context));
+ tpl = new dd.Template('{{ pi|get_digit:0 }}');
+ t.is("314159265", tpl.render(context));
+ tpl = new dd.Template('{{ "nada"|get_digit:1 }}');
+ t.is("0", tpl.render(context));
+ },
+ function test_filter_iriencode(t){
+ var dd = dojox.dtl;
+
+ var tpl = new dd.Template('{{ "http://homepage.com/~user"|urlencode|iriencode }}');
+ t.is("http%3A//homepage.com/%7Euser", tpl.render());
+ tpl = new dd.Template('{{ "pottedmeat@dojotoolkit.org"|iriencode }}');
+ t.is("pottedmeat%40dojotoolkit.org", tpl.render());
+ },
+ function test_filter_join(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ items: ["foo", "bar", "baz" ]});
+ var tpl = new dd.Template("{{ items|join }}");
+ t.is("foo,bar,baz", tpl.render(context));
+
+ tpl = new dd.Template('{{ items|join:"mustard" }}');
+ t.is("foomustardbarmustardbaz", tpl.render(context));
+ },
+ function test_filter_length(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ fruit: [
+ { name: "lemons", toString: function(){ return this.name; } },
+ { name: "apples", toString: function(){ return this.name; } },
+ { name: "grapes", toString: function(){ return this.name; } }
+ ]
+ });
+ tpl = new dd.Template('{{ fruit|length }}');
+ t.is("3", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|first|length }}');
+ t.is("6", tpl.render(context));
+ },
+ function test_filter_length_is(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ fruit: [
+ { name: "lemons", toString: function(){ return this.name; } },
+ { name: "apples", toString: function(){ return this.name; } },
+ { name: "grapes", toString: function(){ return this.name; } }
+ ]
+ });
+ tpl = new dd.Template('{{ fruit|length_is:"3" }}');
+ t.is("true", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|length_is:"4" }}');
+ t.is("false", tpl.render(context));
+ },
+ function test_filter_linebreaks(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ unbroken: "This is just\r\n\n\ra bunch\nof text\n\n\nand such" });
+ tpl = new dd.Template('{{ unbroken|linebreaks }}');
+ t.is("<p>This is just</p>\n\n<p>a bunch<br />of text</p>\n\n<p>and such</p>", tpl.render(context));
+ },
+ function test_filter_linebreaksbr(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ unbroken: "This is just\r\n\n\ra bunch\nof text\n\n\nand such" });
+ tpl = new dd.Template('{{ unbroken|linebreaksbr }}');
+ t.is("This is just<br /><br />a bunch<br />of text<br /><br /><br />and such", tpl.render(context));
+ },
+ function test_filter_linenumbers(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ lines: "One\nTwo\nThree\nFour\n" });
+ var tpl = new dd.Template('{{ lines|linenumbers }}');
+ t.is("1. One\n2. Two\n3. Three\n4. Four\n5. ", tpl.render(context));
+ },
+ function test_filter_ljust(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context();
+ var tpl = new dd.Template('{{ narrow|ljust }}');
+ context.narrow = "even";
+ t.is("even", tpl.render(context));
+ context.narrow = "odd";
+ t.is("odd", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|ljust:"5" }}');
+ context.narrow = "even";
+ t.is("even ", tpl.render(context));
+ context.narrow = "odd";
+ t.is("odd ", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|ljust:"6" }}');
+ context.narrow = "even";
+ t.is("even ", tpl.render(context));
+ context.narrow = "odd";
+ t.is("odd ", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|ljust:"12" }}');
+ context.narrow = "even";
+ t.is("even ", tpl.render(context));
+ context.narrow = "odd";
+ t.is("odd ", tpl.render(context));
+ },
+ function test_filter_lower(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ mixed: "MiXeD" });
+ var tpl = new dd.Template('{{ mixed|lower }}');
+ t.is("mixed", tpl.render(context));
+ },
+ function test_filter_make_list(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ word: "foo", number: 314159265, arr: ["first", "second"], obj: {first: "first", second: "second"} });
+ var tpl = new dd.Template('{{ word|make_list|join:"|" }} {{ number|make_list|join:"|" }} {{ arr|make_list|join:"|" }} {{ obj|make_list|join:"|" }}');
+ t.is("f|o|o 3|1|4|1|5|9|2|6|5 first|second first|second", tpl.render(context));
+ },
+ function test_filter_phone2numeric(t){
+ var dd = dojox.dtl;
+
+ tpl = new dd.Template('{{ "1-800-pottedmeat"|phone2numeric }}');
+ t.is("1-800-7688336328", tpl.render());
+ },
+ function test_filter_pluralize(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ animals: ["bear", "cougar", "aardvark"] });
+ var tpl = new dd.Template('{{ animals|length }} animal{{ animals|length|pluralize }}');
+ t.is("3 animals", tpl.render(context));
+ context.animals = ["bear"];
+ t.is("1 animal", tpl.render(context));
+ context = new dd.Context({ fairies: ["tinkerbell", "Andy Dick" ]});
+ tpl = new dd.Template('{{ fairies|length }} fair{{ fairies|length|pluralize:"y,ies" }}');
+ t.is("2 fairies", tpl.render(context));
+ context.fairies.pop();
+ t.is("1 fairy", tpl.render(context));
+ },
+ function test_filter_pprint(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ animals: ["bear", "cougar", "aardvark"] });
+ tpl = new dd.Template("{{ animals|pprint }}");
+ t.is('["bear","cougar","aardvark"]', tpl.render(context));
+ },
+ function test_filter_random(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ fruit: [
+ { name: "lemons", toString: function(){ return this.name; } },
+ { name: "apples", toString: function(){ return this.name; } },
+ { name: "grapes", toString: function(){ return this.name; } }
+ ]
+ });
+ tpl = new dd.Template('{{ fruit|random }}');
+ result = tpl.render(context);
+ t.t(result == "lemons" || result == "apples" || result == "grapes");
+ var different = false;
+ for(var i = 0; i < 10; i++){
+ // Check to see if it changes
+ if(result != tpl.render(context) && result == "lemons" || result == "apples" || result == "grapes"){
+ different = true;
+ break;
+ }
+ }
+ t.t(different);
+ },
+ function test_filter_removetags(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ tagged: "I'm gonna do something <script>evil</script> with the <html>filter" });
+ tpl = new dd.Template('{{ tagged|removetags:"script <html>" }}');
+ t.is("I'm gonna do something evil with the filter", tpl.render(context));
+ },
+ function test_filter_rjust(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context();
+ var tpl = new dd.Template('{{ narrow|rjust }}');
+ context.narrow = "even";
+ t.is("even", tpl.render(context));
+ context.narrow = "odd";
+ t.is("odd", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|rjust:"5" }}');
+ context.narrow = "even";
+ t.is(" even", tpl.render(context));
+ context.narrow = "odd";
+ t.is(" odd", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|rjust:"6" }}');
+ context.narrow = "even";
+ t.is(" even", tpl.render(context));
+ context.narrow = "odd";
+ t.is(" odd", tpl.render(context));
+ tpl = new dd.Template('{{ narrow|rjust:"12" }}');
+ context.narrow = "even";
+ t.is(" even", tpl.render(context));
+ context.narrow = "odd";
+ t.is(" odd", tpl.render(context));
+ },
+ function test_filter_slice(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ fruit: [
+ { name: "lemons", toString: function(){ return this.name; } },
+ { name: "apples", toString: function(){ return this.name; } },
+ { name: "grapes", toString: function(){ return this.name; } }
+ ]
+ });
+ tpl = new dd.Template('{{ fruit|slice:":1"|join:"|" }}');
+ t.is("lemons", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|slice:"1"|join:"|" }}');
+ t.is("apples|grapes", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|slice:"1:3"|join:"|" }}');
+ t.is("apples|grapes", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|slice:""|join:"|" }}');
+ t.is("lemons|apples|grapes", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|slice:"-1"|join:"|" }}');
+ t.is("grapes", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|slice:":-1"|join:"|" }}');
+ t.is("lemons|apples", tpl.render(context));
+ tpl = new dd.Template('{{ fruit|slice:"-2:-1"|join:"|" }}');
+ t.is("apples", tpl.render(context));
+ },
+ function test_filter_slugify(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ unslugged: "Apples and oranges()"});
+ tpl = new dd.Template('{{ unslugged|slugify }}');
+ t.is("apples-and-oranges", tpl.render(context));
+ },
+ function test_filter_stringformat(t){
+ var dd = dojox.dtl;
+
+ var tpl = new dd.Template('{{ 42|stringformat:"7.3f" }}');
+ t.is(" 42.000", tpl.render());
+ },
+ function test_filter_striptags(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ tagged: "I'm gonna do something <script>evil</script> with the <html>filter" });
+ tpl = new dd.Template('{{ tagged|striptags }}');
+ t.is("I'm gonna do something evil with the filter", tpl.render(context));
+ },
+ function test_filter_time(t){
+ var dd = dojox.dtl;
+ var context = new dd.Context({ now: new Date(2007, 0, 1) });
+
+ tpl = new dd.Template('{{ now|time }}');
+ t.is(dojox.dtl.utils.date.format(context.now, "P"), tpl.render(context));
+ },
+ function test_filter_timesince(t){
+ var dd = dojox.dtl;
+ var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) });
+
+ tpl = new dd.Template('{{ now|timesince:then }}');
+ t.is("1 month", tpl.render(context));
+ context.then = new Date(2007, 0, 5);
+ t.is("4 days", tpl.render(context));
+ context.then = new Date(2007, 0, 17);
+ t.is("2 weeks", tpl.render(context));
+ context.then = new Date(2008, 1, 1);
+ t.is("1 year", tpl.render(context));
+ },
+ function test_filter_timeuntil(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ now: new Date(2007, 0, 1), then: new Date(2007, 1, 1) });
+ var tpl = new dd.Template('{{ now|timeuntil:then }}');
+ t.is("1 month", tpl.render(context));
+ context.then = new Date(2007, 0, 5);
+ t.is("4 days", tpl.render(context));
+ context.then = new Date(2007, 0, 17);
+ t.is("2 weeks", tpl.render(context));
+ context.then = new Date(2008, 1, 1);
+ t.is("1 year", tpl.render(context));
+ },
+ function test_filter_title(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ name: "potted meat" });
+ var tpl = new dd.Template("{{ name|title }}");
+ t.is("Potted Meat", tpl.render(context));
+
+ context.name = "What's going on?";
+ t.is("What's Going On?", tpl.render(context));
+
+ context.name = "use\nline\nbREAKs\tand tabs";
+ t.is("Use\nLine\nBreaks\tAnd Tabs", tpl.render(context));
+ },
+ function test_filter_truncatewords(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ word: "potted meat writes a lot of tests" });
+ var tpl = new dd.Template("{{ word|truncatewords }}");
+ t.is(context.word, tpl.render(context));
+
+ tpl = new dd.Template('{{ word|truncatewords:"1" }}');
+ t.is("potted", tpl.render(context));
+
+ tpl = new dd.Template('{{ word|truncatewords:"2" }}');
+ t.is("potted meat", tpl.render(context));
+
+ tpl = new dd.Template('{{ word|truncatewords:20" }}');
+ t.is(context.word, tpl.render(context));
+
+ context.word = "potted \nmeat \nwrites a lot of tests";
+ tpl = new dd.Template('{{ word|truncatewords:"3" }}');
+ t.is("potted \nmeat \nwrites", tpl.render(context));
+ },
+ function test_filter_truncatewords_html(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ body: "Test a string <em>that ends <i>inside a</i> tag</em> with different args",
+ size: 2
+ })
+ var tpl = new dd.Template('{{ body|truncatewords_html:size }}');
+ t.is("Test a ...", tpl.render(context));
+ context.size = 4;
+ t.is("Test a string <em>that ...</em>", tpl.render(context));
+ context.size = 6;
+ t.is("Test a string <em>that ends <i>inside ...</i></em>", tpl.render(context));
+ },
+ function test_filter_unordered_list(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ states: ["States", [["Kansas", [["Lawrence", []], ["Topeka", []]]], ["Illinois", []]]] });
+ tpl = new dd.Template('{{ states|unordered_list }}');
+ t.is("\t<li>States\n\t<ul>\n\t\t<li>Kansas\n\t\t<ul>\n\t\t\t<li>Lawrence</li>\n\t\t\t<li>Topeka</li>\n\t\t</ul>\n\t\t</li>\n\t\t<li>Illinois</li>\n\t</ul>\n\t</li>", tpl.render(context));
+ },
+ function test_filter_upper(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({ mixed: "MiXeD" });
+ var tpl = new dd.Template('{{ mixed|upper }}');
+ t.is("MIXED", tpl.render(context));
+ },
+ function test_filter_urlencode(t){
+ var dd = dojox.dtl;
+
+ var tpl = new dd.Template('{{ "http://homepage.com/~user"|urlencode }}');
+ t.is("http%3A//homepage.com/%7Euser", tpl.render());
+ },
+ function test_filter_urlize(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ body: "My favorite websites are www.televisionwithoutpity.com, http://daringfireball.net and you can email me at pottedmeat@sitepen.com"
+ });
+ var tpl = new dd.Template("{{ body|urlize }}");
+ t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.televisionwithoutpity.com</a> <a href="http://daringfireball.net" rel="nofollow">http://daringfireball.net</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));
+ },
+ function test_filter_urlizetrunc(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ body: "My favorite websites are www.televisionwithoutpity.com, http://daringfireball.net and you can email me at pottedmeat@sitepen.com"
+ });
+ var tpl = new dd.Template("{{ body|urlizetrunc }}");
+ t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.televisionwithoutpity.com</a> <a href="http://daringfireball.net" rel="nofollow">http://daringfireball.net</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));
+ tpl = new dd.Template('{{ body|urlizetrunc:"2" }}');
+ t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.televisionwithoutpity.com</a> <a href="http://daringfireball.net" rel="nofollow">http://daringfireball.net</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));
+ tpl = new dd.Template('{{ body|urlizetrunc:"10" }}');
+ t.is('My favorite websites are <a href="http://www.televisionwithoutpity.com" rel="nofollow">www.tel...</a> <a href="http://daringfireball.net" rel="nofollow">http://...</a> and you can email me at <a href="mailto:pottedmeat@sitepen.com">pottedmeat@sitepen.com</a>', tpl.render(context));
+ },
+ function test_filter_wordcount(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ food: "Hot Pocket"
+ });
+ var tpl = new dd.Template("{{ food|wordcount }}");
+ t.is("2", tpl.render(context));
+ context.food = "";
+ t.is("0", tpl.render(context));
+ context.food = "A nice barbecue, maybe a little grilled veggies, some cole slaw.";
+ t.is("11", tpl.render(context));
+ },
+ function test_filter_wordwrap(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ body: "shrimp gumbo, shrimp pie, shrimp scampi, shrimp stew, fried shrimp, baked shrimp, shrimp o grotten, grilled shrimp, shrimp on a stick, shrimp salad, shrimp pop overs, shrimp cake, shrimp legs, shrimp stuffed eggs, shrimp cre oll, shrimp soup, creamed shrimp on toast, shrimp crapes, shrimply good crescent rolls, shrimp pizza, scalloped shrimp, boiled shrimp, shrimp cocktail"
+ });
+ var tpl = new dd.Template("{{ body|wordwrap }}");
+ t.is(context.body, tpl.render(context));
+ tpl = new dd.Template("{{ body|wordwrap:width }}");
+ context.width = 10;
+ t.is("shrimp\ngumbo,\nshrimp\npie,\nshrimp\nscampi,\nshrimp\nstew,\nfried\nshrimp,\nbaked\nshrimp,\nshrimp o\ngrotten,\ngrilled\nshrimp,\nshrimp on\na stick,\nshrimp\nsalad,\nshrimp pop\novers,\nshrimp\ncake,\nshrimp\nlegs,\nshrimp\nstuffed\neggs,\nshrimp cre\noll,\nshrimp\nsoup,\ncreamed\nshrimp on\ntoast,\nshrimp\ncrapes,\nshrimply\ngood\ncrescent\nrolls,\nshrimp\npizza,\nscalloped\nshrimp,\nboiled\nshrimp,\nshrimp\ncocktail", tpl.render(context));
+ tpl = new dd.Template('{{ body|wordwrap:"80" }}');
+ t.is("shrimp gumbo, shrimp pie, shrimp scampi, shrimp stew, fried shrimp, baked\nshrimp, shrimp o grotten, grilled shrimp, shrimp on a stick, shrimp salad,\nshrimp pop overs, shrimp cake, shrimp legs, shrimp stuffed eggs, shrimp cre oll,\nshrimp soup, creamed shrimp on toast, shrimp crapes, shrimply good crescent\nrolls, shrimp pizza, scalloped shrimp, boiled shrimp, shrimp cocktail", tpl.render(context));
+ },
+ function test_filter_yesno(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context();
+ tpl = new dd.Template('{{ true|yesno }}');
+ t.is("yes", tpl.render(context));
+ context = new dd.Context({ test: "value" });
+ tpl = new dd.Template('{{ test|yesno }}');
+ t.is("yes", tpl.render(context));
+ tpl = new dd.Template('{{ false|yesno }}');
+ t.is("no", tpl.render(context));
+ tpl = new dd.Template('{{ null|yesno }}');
+ t.is("maybe", tpl.render(context));
+ tpl = new dd.Template('{{ true|yesno:"bling,whack,soso" }}');
+ t.is("bling", tpl.render(context));
+ context = new dd.Context({ test: "value" });
+ tpl = new dd.Template('{{ test|yesno:"bling,whack,soso" }}');
+ t.is("bling", tpl.render(context));
+ tpl = new dd.Template('{{ false|yesno:"bling,whack,soso" }}');
+ t.is("whack", tpl.render(context));
+ tpl = new dd.Template('{{ null|yesno:"bling,whack,soso" }}');
+ t.is("soso", tpl.render(context));
+ tpl = new dd.Template('{{ null|yesno:"bling,whack" }}');
+ t.is("whack", tpl.render(context));
+ },
+ function test_filter_contrib_key(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ headers: ["action", "type"],
+ items: [
+ {
+ action: "eat",
+ type: "apple",
+ },
+ {
+ action: "mash",
+ type: "banana"
+ }
+ ]
+ });
+
+ var tpl = new dd.Template("{% load dojox.dtl.contrib.objects %}<ul>{% for item in items %}<li><ul>{% for header in headers %}<li>{{ header }}: {{ item|key:header }}</li>{% endfor %}</ul></li>{% endfor %}</ul>");
+ t.is('<ul><li><ul><li>action: eat</li><li>type: apple</li></ul></li><li><ul><li>action: mash</li><li>type: banana</li></ul></li></ul>', tpl.render(context));
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/dtl/tests/text/load.js b/includes/js/dojox/dtl/tests/text/load.js
new file mode 100644
index 0000000..b4c7472
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/text/load.js
@@ -0,0 +1,6 @@
+if(!dojo._hasResource["dojox.dtl.tests.text.load"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.text.load"] = true;
+dojo.provide("dojox.dtl.tests.text.load");
+// Test for the {% load %} tag
+
+}
diff --git a/includes/js/dojox/dtl/tests/text/tag.js b/includes/js/dojox/dtl/tests/text/tag.js
new file mode 100644
index 0000000..7abbc43
--- /dev/null
+++ b/includes/js/dojox/dtl/tests/text/tag.js
@@ -0,0 +1,480 @@
+if(!dojo._hasResource["dojox.dtl.tests.text.tag"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.tests.text.tag"] = true;
+dojo.provide("dojox.dtl.tests.text.tag");
+
+dojo.require("dojox.dtl");
+dojo.require("dojox.dtl.Context");
+
+doh.register("dojox.dtl.text.tag",
+ [
+ function test_tag_block_and_extends(t){
+ var dd = dojox.dtl;
+
+ // Simple (messy) string-based extension
+ var template = new dd.Template('{% extends "../../dojox/dtl/tests/templates/pocket.html" %}{% block pocket %}Simple{% endblock %}');
+ t.is("Simple Pocket", template.render());
+
+ // Variable replacement
+ var context = new dd.Context({
+ parent: "../../dojox/dtl/tests/templates/pocket.html"
+ })
+ template = new dd.Template('{% extends parent %}{% block pocket %}Variabled{% endblock %}');
+ t.is("Variabled Pocket", template.render(context));
+
+ // Nicer dojo.moduleUrl and variable based extension
+ context.parent = dojo.moduleUrl("dojox.dtl.tests.templates", "pocket.html");
+ template = new dd.Template('{% extends parent %}{% block pocket %}Slightly More Advanced{% endblock %}');
+ t.is("Slightly More Advanced Pocket", template.render(context));
+
+ // dojo.moduleUrl with support for more variables.
+ // This is important for HTML templates where the "shared" flag will be important.
+ context.parent = {
+ url: dojo.moduleUrl("dojox.dtl.tests.templates", "pocket.html")
+ }
+ template = new dd.Template('{% extends parent %}{% block pocket %}Super{% endblock %}');
+ t.is("Super Pocket", template.render(context));
+ },
+ function test_tag_block(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ parent: dojo.moduleUrl("dojox.dtl.tests.templates", "pocket2.html"),
+ items: ["apple", "banana", "lemon" ]
+ });
+
+ var template = new dd.Template("{% extends parent %}{% block pocket %}My {{ item }}{% endblock %}");
+ t.is("(My apple) (My banana) (My lemon) Pocket", template.render(context));
+ },
+ function test_tag_comment(t){
+ var dd = dojox.dtl;
+
+ var template = new dd.Template('Hot{% comment %}<strong>Make me disappear</strong>{% endcomment %} Pocket');
+ t.is("Hot Pocket", template.render());
+
+ var found = false;
+ try{
+ template = new dd.Template('Hot{% comment %}<strong>Make me disappear</strong> Pocket');
+ }catch(e){
+ t.is("Unclosed tag found when looking for endcomment", e.message);
+ found = true;
+ }
+ t.t(found);
+ },
+ function test_tag_cycle(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ items: ["apple", "banana", "lemon"],
+ unplugged: "Torrey"
+ });
+ var template = new dd.Template("{% for item in items %}{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' %} Pocket. {% endfor %}");
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context));
+ // Make sure that it doesn't break on re-render
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context));
+
+ // Test repeating the loop
+ context.items.push("guava", "mango", "pineapple");
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. Extra Pocket. Hot Pocket. Diarrhea Pocket. ", template.render(context));
+
+ // Repeat the above tests for the old style
+ // ========================================
+ context.items = context.items.slice(0, 3);
+ template = new dd.Template("{% for item in items %}{% cycle Hot,Diarrhea,Torrey,Extra %} Pocket. {% endfor %}");
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context));
+ // Make sure that it doesn't break on re-render
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context));
+
+ // Test repeating the loop
+ context.items.push("guava", "mango", "pineapple");
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. Extra Pocket. Hot Pocket. Diarrhea Pocket. ", template.render(context));
+
+ // Now test outside of the for loop
+ // ================================
+ context = new dojox.dtl.Context({ unplugged: "Torrey" });
+ template = new dd.Template("{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' as steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket.");
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket.", template.render(context));
+
+ template = new dd.Template("{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' as steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket. {% cycle steakum %} Pocket.");
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. Extra Pocket. Hot Pocket. Diarrhea Pocket.", template.render(context));
+//t.t(false)
+ // Test for nested objects
+ context.items = {
+ list: ["apple", "banana", "lemon"]
+ };
+ template = new dd.Template("{% for item in items.list %}{% cycle 'Hot' 'Diarrhea' unplugged 'Extra' %} Pocket. {% endfor %}");
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context));
+ // Make sure that it doesn't break on re-render
+ t.is("Hot Pocket. Diarrhea Pocket. Torrey Pocket. ", template.render(context));
+ },
+ function test_tag_debug(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ items: ["apple", "banana", "lemon"],
+ unplugged: "Torrey"
+ });
+ var template = new dd.Template("{% debug %}");
+ t.is('items: ["apple","banana","lemon"]\n\nunplugged: "Torrey"\n\n', template.render(context));
+ },
+ function test_tag_filter(t){
+ var dd = dojox.dtl;
+
+ var template = new dd.Template('{% filter lower|center:"15" %}Hot Pocket{% endfilter %}');
+ t.is(" hot pocket ", template.render());
+ },
+ function test_tag_firstof(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ found: "unicorn"
+ });
+
+ var template = new dd.Template("{% firstof one two three four found %}");
+ t.is("unicorn", template.render(context));
+
+ context.four = null;
+ t.is("null", template.render(context));
+
+ context.three = false;
+ t.is("false", template.render(context));
+ },
+ function test_tag_for(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ items: ["apple", "banana", "lemon"]
+ });
+ var template = new dd.Template("{% for item in items %}<li>{{ item }}</li>{% endfor %}");
+ t.is("<li>apple</li><li>banana</li><li>lemon</li>", template.render(context));
+
+ template = new dd.Template("{% for item in items reversed %}<li>{{ item }}</li>{% endfor %}");
+ t.is("<li>lemon</li><li>banana</li><li>apple</li>", template.render(context));
+
+ context.items = {
+ apple: "Red Delicious",
+ banana: "Cavendish",
+ lemon: "Citrus"
+ };
+ template = new dd.Template("{% for key, value in items.items %}<li>{{ value }} {{ key|title }}</li>{% endfor %}");
+ t.is("<li>Red Delicious Apple</li><li>Cavendish Banana</li><li>Citrus Lemon</li>", template.render(context));
+
+ // The same thing above, but using "zipped" sets
+ context.items = [
+ ["apple", "Red Delicious", 1.99],
+ ["banana", "Cavendish", 0.49],
+ ["lemon", "Citrus", 0.29]
+ ];
+ template = new dd.Template("{% for fruit, type, price in items %}<li>{{ type }} {{ fruit|title }} costs ${{ price}}</li>{% endfor %}");
+ t.is("<li>Red Delicious Apple costs $1.99</li><li>Cavendish Banana costs $0.49</li><li>Citrus Lemon costs $0.29</li>", template.render(context));
+
+ template = new dd.Template("{% for fruit, type, price in items reversed %}<li>{{ type }} {{ fruit|title }} costs ${{ price}}</li>{% endfor %}");
+ t.is("<li>Citrus Lemon costs $0.29</li><li>Cavendish Banana costs $0.49</li><li>Red Delicious Apple costs $1.99</li>", template.render(context));
+
+ // Now to create some errors
+ var found = false;
+ try {
+ template = new dd.Template("{% for item initems %}<li>{{ item }}</li>{% endfor %}");
+ }catch(e){
+ found = true;
+ t.is("'for' statements should have at least four words: for item initems", e.message);
+ }
+ t.t(found);
+
+ found = false;
+ try {
+ template = new dd.Template("{% for item ni items %}<li>{{ item }}</li>{% endfor %}");
+ }catch(e){
+ found = true;
+ t.is("'for' tag received an invalid argument: for item ni items", e.message);
+ }
+ t.t(found);
+
+ found = false;
+ try {
+ template = new dd.Template("{% for my item in items %}<li>{{ item }}</li>{% endfor %}");
+ }catch(e){
+ found = true;
+ t.is("'for' tag received an invalid argument: for my item in items", e.message);
+ }
+ t.t(found);
+ },
+ function test_tag_if(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ jokes: {
+ hot_pockets: true,
+ unicycles: true,
+ bacon: true
+ }
+ });
+ var template = new dd.Template("Comedian is {% if jokes.hot_pockets and jokes.unicycles and jokes.bacon %}funny{% else %}not funny{% endif %}");
+ t.is("Comedian is funny", template.render(context));
+
+ context.jokes.unicycles = false;
+ t.is("Comedian is not funny", template.render(context));
+
+ context.comedians = {
+ hedberg: true,
+ gaffigan: true,
+ cook: true
+ };
+ template = new dd.Template("Show will be {% if comedians.hedberg or comedians.gaffigan %}worth seeing{% else %}not worth seeing{% endif %}");
+ t.is("Show will be worth seeing", template.render(context));
+
+ // NOTE: "and" is implied by nesting. eg {% if sunny %}{% if windy %}It's Sunny and Windy{% endif %}{% endif %}
+ // Not mixing ands and ors allows for MUCH faster rendering
+ template = new dd.Template("Show will {% if comedians.hedberg or comedians.gaffigan %}{% if comedians.cook %}not {% endif %}be worth seeing{% else %}not be worth seeing{% endif %}");
+ t.is("Show will not be worth seeing", template.render(context));
+
+ context.comedians.cook = false;
+ t.is("Show will be worth seeing", template.render(context));
+
+ template = new dd.Template("Show will be {% if comedians.hedberg and comedians.gaffigan and not comedians.cook %}AWESOME{% else %}almost awesome{% endif %}");
+ t.is("Show will be AWESOME", template.render(context));
+
+ context.comedians.cook = true;
+ t.is("Show will be almost awesome", template.render(context));
+
+ // Now we test for errors.
+ var found = false;
+ try {
+ template = new dd.Template("Show will be {% if comedians.hedberg or comedians.gaffigan and not comedians.cook %}worth seeing{% else %}not worth seeing{% endif %}");
+ }catch(e){
+ found = true;
+ t.is("'if' tags can't mix 'and' and 'or'", e.message);
+ }
+ t.t(found);
+ },
+ function test_tag_ifchanged(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ year: 2008,
+ days: [
+ new Date(2008, 0, 12),
+ new Date(2008, 0, 28),
+ new Date(2008, 1, 1),
+ new Date(2008, 1, 1),
+ new Date(2008, 1, 1)
+ ]
+ });
+
+ var template = new dd.Template("<h1>Archive for {{ year }}</h1>"+
+"{% for date in days %}"+
+'{% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}'+
+'<a href="{{ date|date:\'M/d\'|lower }}/">{{ date|date:\'j\' }}</a>'+
+"{% endfor %}");
+ t.is('<h1>Archive for 2008</h1>'+
+'<h3>January</h3>'+
+'<a href="jan/12/">12</a>'+
+'<a href="jan/28/">28</a>'+
+'<h3>February</h3>'+
+'<a href="feb/01/">1</a>'+
+'<a href="feb/01/">1</a>'+
+'<a href="feb/01/">1</a>', template.render(context));
+
+ template = new dd.Template('{% for date in days %}'+
+'{% ifchanged date.date %} {{ date.date }} {% endifchanged %}'+
+'{% ifchanged date.hour date.date %}'+
+'{{ date.hour }}'+
+'{% endifchanged %}'+
+'{% endfor %}');
+ t.is(' 2008-01-12 0 2008-01-28 0 2008-02-01 0', template.render(context));
+ },
+ function test_tag_ifequal(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ user: {
+ id: 314
+ },
+ comment: {
+ user_id: 314
+ }
+ });
+
+ var template = new dd.Template("{% ifequal user.id comment.user_id %}You posted this{% endifequal %}");
+ t.is("You posted this", template.render(context));
+
+ context.user.id = 313;
+ t.is("", template.render(context));
+
+ // Errors
+ var found = false;
+ try {
+ template = new dd.Template("{% ifequal user.id %}You posted this{% endifequal %}");
+ }catch(e){
+ found = true;
+ t.is("ifequal takes two arguments", e.message);
+ }
+ t.t(found);
+
+ found = false;
+ try {
+ template = new dd.Template("{% ifequal user.id comment.user_id %}You posted this{% endif %}");
+ }catch(e){
+ found = true;
+ t.is("No tag found for endif", e.message);
+ }
+ t.t(found);
+ },
+ function test_tag_ifnotequal(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ favorite: "hedberg",
+ comedian: "cook"
+ });
+
+ var template = new dd.Template("{% ifnotequal favorite comedian %}Not your favorite{% else %}Your favorite{% endifnotequal %}");
+ t.is("Not your favorite", template.render(context));
+
+ context.comedian = "hedberg";
+ t.is("Your favorite", template.render(context));
+ },
+ function test_tag_include(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"),
+ person: "Bob",
+ people: ["Charles", "Ralph", "Julia"]
+ });
+
+ var template = new dd.Template("{% include hello %}");
+ t.is("Hello, <span>Bob</span>", template.render(context));
+
+ template = new dd.Template('{% include "../../dojox/dtl/tests/templates/hello.html" %}');
+ t.is("Hello, <span>Bob</span>", template.render(context));
+
+ template = new dd.Template('{% for person in people %}{% include hello %} {% endfor %}');
+ t.is("Hello, <span>Charles</span> Hello, <span>Ralph</span> Hello, <span>Julia</span> ", template.render(context));
+ },
+ function test_tag_load(t){
+ t.f(dojox.dtl.tests.text.load);
+ new dojox.dtl.Template("{% load dojox.dtl.tests.text.load %}");
+ t.t(dojox.dtl.tests.text.load);
+ },
+ function test_tag_now(t){
+ var dd = dojox.dtl;
+
+ var template = new dd.Template('It is {% now "jS F Y H:i" %}');
+ t.t(template.render().match(/^It is \d{1,2}[a-z]{2} [A-Z][a-z]+ [0-9]{4,} \d{2}:\d{2}$/));
+
+ template = new dd.Template('It is the {% now "jS \\o\\f F" %}');
+ t.t(template.render().match(/^It is the \d{1,2}[a-z]{2} of [A-Z][a-z]+$/));
+
+ template = new dd.Template("It is the {% now 'jS \\o\\f F' %}");
+ t.t(template.render().match(/^It is the \d{1,2}[a-z]{2} of [A-Z][a-z]+$/));
+
+ var found = false;
+ try{
+ template = new dd.Template("It is the {% now 'jS \\o\\f F %}");
+ }catch(e){
+ found = true;
+ t.is("'now' statement takes one argument", e.message);
+ }
+ t.t(found);
+
+ found = false;
+ try{
+ template = new dd.Template('It is the {% now "jS \\o\\f F %}');
+ }catch(e){
+ found = true;
+ t.is("'now' statement takes one argument", e.message);
+ }
+ t.t(found);
+ },
+ function test_tag_regroup(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ people: [
+ { firstName: "Bill", lastName: "Clinton", gender: "Male" },
+ { firstName: "Margaret", lastName: "Thatcher", gender: "Female" },
+ { firstName: "Path", lastName: "Smith", gender: "Unkown" },
+ { firstName: "Condoleezza", lastName: "Rice", gender: "Female" },
+ { firstName: "George", lastName: "Bush", gender: "Male" }
+ ]
+ });
+
+ var template = new dd.Template("{% regroup people|dictsort:'gender' by gender as grouped %}<ul>{% for group in grouped %}<li>{{ group.grouper }}<ul>{% for item in group.list %}<li>{{ item.firstName }} {{ item.lastName }}</li>{% endfor %}</ul></li>{% endfor %}</ul>");
+ t.t(template.render(context).match(new RegExp("^<ul><li>Female<ul><li>(Condoleezza Rice|Margaret Thatcher)</li><li>(Condoleezza Rice|Margaret Thatcher)</li></ul></li><li>Male<ul><li>(Bill Clinton|George Bush)</li><li>(Bill Clinton|George Bush)</li></ul></li><li>Unkown<ul><li>Path Smith</li></ul></li></ul>$")));
+ },
+ function test_tag_spaceless(t){
+ var dd = dojox.dtl;
+
+ var template = new dd.Template("{% spaceless %}<ul> \n <li>Hot</li> \n\n<li>Pocket </li>\n </ul>{% endspaceless %}");
+ t.is("<ul><li>Hot</li><li>Pocket </li></ul>", template.render());
+ },
+ function test_tag_ssi(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ hello: dojo.moduleUrl("dojox.dtl.tests.templates", "hello.html"),
+ person: "Bob",
+ people: ["Charles", "Ralph", "Julia"]
+ });
+
+ var template = new dd.Template("{% ssi hello parsed %}");
+ t.is("Hello, <span>Bob</span>", template.render(context));
+
+ template = new dd.Template("{% ssi hello %}");
+ t.is("Hello, <span>{{ person }}</span>", template.render(context));
+
+ template = new dd.Template('{% ssi "../../dojox/dtl/tests/templates/hello.html" parsed %}');
+ t.is("Hello, <span>Bob</span>", template.render(context));
+
+ template = new dd.Template('{% for person in people %}{% ssi hello parsed %} {% endfor %}');
+ t.is("Hello, <span>Charles</span> Hello, <span>Ralph</span> Hello, <span>Julia</span> ", template.render(context));
+ },
+ function test_tag_templatetag(t){
+ var dd = dojox.dtl;
+
+ var template = new dd.Template("{% templatetag openblock %}");
+ t.is("{%", template.render());
+ template = new dd.Template("{% templatetag closeblock %}");
+ t.is("%}", template.render());
+ template = new dd.Template("{% templatetag openvariable %}");
+ t.is("{{", template.render());
+ template = new dd.Template("{% templatetag closevariable %}");
+ t.is("}}", template.render());
+ template = new dd.Template("{% templatetag openbrace %}");
+ t.is("{", template.render());
+ template = new dd.Template("{% templatetag closebrace %}");
+ t.is("}", template.render());
+ template = new dd.Template("{% templatetag opencomment %}");
+ t.is("{#", template.render());
+ template = new dd.Template("{% templatetag closecomment %}");
+ t.is("#}", template.render());
+ },
+ function test_tag_widthratio(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ this_value: 175,
+ max_value: 200
+ });
+
+ var template = new dd.Template('<img src="bar.gif" height="10" width="{% widthratio this_value max_value 100 %}" />');
+ t.is('<img src="bar.gif" height="10" width="88" />', template.render(context));
+ },
+ function test_tag_with(t){
+ var dd = dojox.dtl;
+
+ var context = new dd.Context({
+ person: {
+ someSqlMethod: function(){
+ return 4815162342;
+ }
+ }
+ });
+
+ var template = new dd.Template('{% with person.someSqlMethod as total %}{{ total }} object{{ total|pluralize }}{% endwith %}')
+ t.is("4815162342 objects", template.render(context));
+ }
+ ]
+);
+
+}
diff --git a/includes/js/dojox/dtl/utils/date.js b/includes/js/dojox/dtl/utils/date.js
new file mode 100644
index 0000000..65f8cb5
--- /dev/null
+++ b/includes/js/dojox/dtl/utils/date.js
@@ -0,0 +1,72 @@
+if(!dojo._hasResource["dojox.dtl.utils.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.dtl.utils.date"] = true;
+dojo.provide("dojox.dtl.utils.date");
+
+dojo.require("dojox.date.php");
+
+dojox.dtl.utils.date.DateFormat = function(/*String*/ format){
+ dojox.date.php.DateFormat.call(this, format);
+}
+dojo.extend(dojox.dtl.utils.date.DateFormat, dojox.date.php.DateFormat.prototype, {
+ f: function(){
+ // summary:
+ // Time, in 12-hour hours and minutes, with minutes left off if they're zero.
+ // description:
+ // Examples: '1', '1:30', '2:05', '2'
+ // Proprietary extension.
+ return (!this.date.getMinutes()) ? this.g() : this.g() + ":" + this.i();
+ },
+ N: function(){
+ // summary: Month abbreviation in Associated Press style. Proprietary extension.
+ return dojox.dtl.utils.date._months_ap[this.date.getMonth()];
+ },
+ P: function(){
+ // summary:
+ // Time, in 12-hour hours, minutes and 'a.m.'/'p.m.', with minutes left off
+ // if they're zero and the strings 'midnight' and 'noon' if appropriate.
+ // description:
+ // Examples: '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.'
+ // Proprietary extension.
+ if(!this.date.getMinutes() && !this.date.getHours()) return 'midnight';
+ if(!this.date.getMinutes() && this.date.getHours() == 12) return 'noon';
+ return this.f() + " " + this.a();
+ }
+});
+
+dojo.mixin(dojox.dtl.utils.date, {
+ format: function(/*Date*/ date, /*String*/ format){
+ var df = new dojox.dtl.utils.date.DateFormat(format);
+ return df.format(date);
+ },
+ timesince: function(d, now){
+ // summary:
+ // Takes two datetime objects and returns the time between then and now
+ // as a nicely formatted string, e.g "10 minutes"
+ // description:
+ // Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
+ if(!(d instanceof Date)){
+ d = new Date(d.year, d.month, d.day);
+ }
+ if(!now){
+ now = new Date();
+ }
+
+ var delta = Math.abs(now.getTime() - d.getTime());
+ for(var i = 0, chunk; chunk = dojox.dtl.utils.date._chunks[i]; i++){
+ var count = Math.floor(delta / chunk[0]);
+ if(count) break;
+ }
+ return count + " " + chunk[1](count);
+ },
+ _chunks: [
+ [60 * 60 * 24 * 365 * 1000, function(n){ return (n == 1) ? 'year' : 'years'; }],
+ [60 * 60 * 24 * 30 * 1000, function(n){ return (n == 1) ? 'month' : 'months'; }],
+ [60 * 60 * 24 * 7 * 1000, function(n){ return (n == 1) ? 'week' : 'weeks'; }],
+ [60 * 60 * 24 * 1000, function(n){ return (n == 1) ? 'day' : 'days'; }],
+ [60 * 60 * 1000, function(n){ return (n == 1) ? 'hour' : 'hours'; }],
+ [60 * 1000, function(n){ return (n == 1) ? 'minute' : 'minutes'; }]
+ ],
+ _months_ap: ["Jan.", "Feb.", "March", "April", "May", "June", "July", "Aug.", "Sept.", "Oct.", "Nov.", "Dec."]
+});
+
+}