<!-- This is the widgets-in-template that composes the application UI of TodoMVC (Dojo 1.8 version) -->
<!--
Notes:
data-dojo-id creates object reference of the widget. Though TodoMVC application does not have multiple instances of this widgets-in-template, "${id}_" prefix is added to data-dojo-id attribute to avoid ID duplication.
-->
<!--
This <script> tag assigns module references to variables that can be used in this template. The modules used here are:
- dojox/mvc/at: Function to create a pointer to dojo/Stateful, for the purpose of data binding
- todo/model/SimpleTodoModel: The data model class for TodoMVC data
- todo/misc/HashSelectedConverter: dojox/mvc data converter for widgets of the <a> tags for All/Active/Completed, for the selected state of the <a> tags
- todo/misc/LessThanOrEqualToConverter: dojox/mvc data converter for the shown/hidden state of "s" in "items left", as well as for the check box to mark all todo items complete/incomplete
<!-- A Dojo Object Store for fetching/saving data from/to localStorage -->
<spandata-dojo-id="${id}_localStorage"
data-dojo-type="todo/store/LocalStorage"></span>
<!--
Our custom controller, based on dojox/mvc/EditStoreRefController, that loads and saves data using a Dojo Object Store, and provides references to the data model (from the Dojo Object Store).
The complete attribute (count of completed todo items, coming as a reference in the data model) is bound to the parent widgets-in-template, so that it can update a CSS class in its root DOM node.
Our custom controller, based on dojox/mvc/ModelRefController, that provides references to the todo list in data model, and handles actions like adding/removing/marking.
The model attribute (the todo list in data model) is bound to above todo/ctrl/TodoRefController instance, so that it's updated as soon as todo/ctrl/TodoRefController obtains the data from Dojo Object Store.
The length attribute (count of all todo items, coming as a reference in the todo list in the data model) is bound to the parent widgets-in-template, so that it can update a CSS class in its root DOM node.
<spanclass="ui-tooltip-top"style="display:none;">Press Enter to save this task</span>
</header>
<sectionid="main">
<!--
The check box to mark todo items complete/incomplete.
It's automatically checked when there is no incomplete items, by the data binding to the count of incomplete todo items (via the todo/ctrl/TodoRefController instance), which is converted to a boolean state representing whether there is no incomplete todo items.
<labelfor="toggle-all">Mark all as complete</label>
<!--
The todo list UI, composed by repeating <li> for each todo item with dojox/mvc/WidgetList.
The children attribute (the list of the todo items) is bound to the todo/ctrl/TodoListRefController instance, so that it's updated as soon as todo/ctrl/TodoRefController obtains the data from Dojo Object Store.
Each <li> is created along with a widgets-in-template associated with it.
Each widgets-in-template here does:
- Associate completed attribute to the existence of "completed" CSS class of its root DOM node (Such association is used by todo/_CssToggleMixin code)
- Associate hidden attribute to the existence of "hidden" CSS class of its root DOM node (Such association is used by todo/_CssToggleMixin code)
- Mix-in in todo/_CssToggleMixin as well as todo/ctrl/_HashCompletedMixin, so that the combination of URL hash and todo item's completed state will end up with the shown/hidden states being updated (by adding/removing "hidden" CSS class)
- Bind its uniqueId attribute to the data model for the todo item, so that the action handler for removing a todo item can specify which todo item should be removed
- Bind its completed attribute to the data model for the todo item, so that todo/ctrl/_HashCompletedMixin code can determine the shown/hidden state with the URL hash
- Bind its hash attribute to the todo/ctrl/RouteController instance, so that todo/ctrl/_HashCompletedMixin code can determine the shown/hidden state with the completed state
The value attribute is associated with the text in this widget, and bound to the todo/ctrl/TodoRefController instance, so that the count of incomplete todo items is updated as soon as todo/ctrl/TodoRefController obtains the data from Dojo Object Store.
The single attribute is associated with the existence of "plural" CSS class of its root DOM node. (Such association is used by todo/_CssToggleMixin code)
The single attribute is bound to the todo/ctrl/TodoRefController instance, so that the state whether the count of incomplete todo item is less than or equal to 1 is updated as soon as todo/ctrl/TodoRefController obtains the data from Dojo Object Store.
<!-- Remove this if you don't implement routing -->
<ulid="filters">
<li>
<!--
The link to show all todo items.
The selected attribute is associated with the existence of "selected" CSS class of its root DOM node. (Such association is used by todo/_CssToggleMixin code)
The selected attribute is bound to todo/ctrl/RouteController instance, so that change in URL hash will be reflected here.
The URL hash is converted to the state whether the hash matches to the href here, by HashSelectedConverter (a dojox/mvc data converter).
The selected attribute is associated with the existence of "selected" CSS class of its root DOM node. (Such association is used by todo/_CssToggleMixin code)
The selected attribute is bound to todo/ctrl/RouteController instance, so that change in URL hash will be reflected here.
The URL hash is converted to the state whether the hash matches to the href here, by HashSelectedConverter (a dojox/mvc data converter).
The selected attribute is associated with the existence of "selected" CSS class of its root DOM node. (Such association is used by todo/_CssToggleMixin code)
The selected attribute is bound to todo/ctrl/RouteController instance, so that change in URL hash will be reflected here.
The URL hash is converted to the state whether the hash matches to the href here, by HashSelectedConverter (a dojox/mvc data converter).
The value attribute is associated with the text in this widget, and bound to the todo/ctrl/TodoRefController instance, so that the count of completed todo items is updated as soon as todo/ctrl/TodoRefController obtains the data from Dojo Object Store.
// A widgets-in-template widget that composes the application UI of TodoMVC (Dojo 1.8 version).
// Also, this class inherits todo/_CssToggleMixin so that it can react to change in "present"/"complete" attributes and add/remove CSS class to the root DOM node of this widget.
// templateString: String
// The HTML of widget template.
templateString:template,
// _setPresentAttr: Object
// A object used by todo/_CssToggleMixin to reflect true/false state of "present" attribute to existence of "todos_present" CSS class in this widget's root DOM.
// A object used by todo/_CssToggleMixin to reflect true/false state of "complete" attribute to existence of "todos_selected" CSS class in this widget's root DOM.
// Kicks off instantiation of this controller, in a similar manner as dijit/_WidgetBase.postscript().
// params: Object?
// The optional parameters for this controller.
// srcNodeRef: DOMNode?
// The DOM node declaring this controller. Set if this controller is created via Dojo parser.
this.inherited(arguments);
srcNodeRef&&srcNodeRef.setAttribute("widgetId",this.id);// If this is created via Dojo parser, set widgetId attribute so that destroyDescendants() of parent widget works
},
startup:function(){
// summary:
// A function called after the DOM fragment declaring this controller is added to the document, in a similar manner as dijit/_WidgetBase.startup().
var_self=this;
this.own(router.register(/.*/,function(e){// Register a route handling callback for any route, make sure it's cleaned up upon this controller being destroyed
// Removes a todo item having the given unique ID.
// uniqueId: String
// The unique ID of the todo item to be removed.
varmodel=this[this._refModelProp],
indices=array.filter(array.map(model,function(item,idx){returnitem.uniqueId==uniqueId?idx:-1;}),function(idx){returnidx>=0;});// The array index of the todo item to bd removed
if(indices.length>0){
model.splice(indices[0],1);
}
},
removeCompletedItems:function(){
// summary:
// Removes todo items that have been marked as complete.
varmodel=this[this._refModelProp];
for(vari=model.length-1;i>=0;--i){
if(model[i].get("completed")){
model.splice(i,1);
}
}
},
markAll:function(/*Boolean*/markComplete){
// summary:
// Mark all todo items as complete or incomplete.
// markComplete: Boolean
// True to mark all todo items as complete. Otherwise to mark all todo items as incomplete.
// - Provide references to the data model, whose data comes from above Dojo Object Store
// defaultId: String
// The default ID to fetch data as this controller starts up.
defaultId:"",
// store: dojo/store
// Our custom Dojo Object Store, backed by localStorage.
// This will be used to read the initial items, if available, and persist the current items when the application finishes.
store:null,
// modelClass: todo/model/SimpleTodoModel
// The class of our data model, based on dojo/Stateful and dojox/mvc/StatefulArray.
// This will be used to automatically keep various Todo properties (e.g. number of complete/incomplete items) consistent, and to auto-generate properties (e.g. default unique IDs).
modelClass:null,
getStatefulOptions:{
// summary:
// An object that specifies how plain object from Dojo Object Store should be converted to a data model based on dojo/Stateful and dojox/mvc/StatefulArray.
getType:function(/*Object*/v){
return"specifiedModel";// We are converting given object at once using modelClass here, instead of using per-data-item based data conversion callbacks
},
getStatefulSpecifiedModel:function(/*Object*/o){
returnnew(this.parent.modelClass)(o);// Create an instance of modelClass given the plain object from Dojo Object Store
}
},
getPlainValueOptions:{
// summary:
// An object that specifies how a data model based on dojo/Stateful and dojox/mvc/StatefulArray should be converted to a plain object, to be saved to Dojo Object Store.
// Kicks off instantiation of this controller, in a similar manner as dijit/_WidgetBase.postscript().
// params: Object?
// The optional parameters for this controller.
// srcNodeRef: DOMNode?
// The DOM node declaring this controller. Set if this controller is created via Dojo parser.
this.getStatefulOptions.parent=this;// For getStatefulOptions object to have a reference to this object
this.inherited(arguments);
srcNodeRef&&srcNodeRef.setAttribute("widgetId",this.id);// If this is created via Dojo parser, set widgetId attribute so that destroyDescendants() of parent widget works
},
startup:function(){
// summary:
// A function called after the DOM fragment declaring this controller is added to the document, in a similar manner as dijit/_WidgetBase.startup().
this.inherited(arguments);
this.getStore(this.defaultId);// Obtain data from Dojo Object Store as soon as this starts up
},
set:function(/*String*/name,/*Anything*/value){
// summary:
// A function called when a property value is set to this controller.
// A dojox/mvc data converter, that does one-way conversion that returns whether we have less than n todo items in a specific state, where n is the given number in data converter options.
// Data converter options can be specified by setting constraints property in one of data binding endpoints.
// See data converter section of dojox/mvc/sync library's documentation for more details.
varstatefulData=getStateful(data||defaultData);// Convert a plain object to dojo/Stateful, hierarchically. Use the default data if (lastly saved) data is not there
array.forEach(statefulData.todos,assignPropertiesToNewItem);// Add additional properties to todo items
// This is a build profile for Dojo version of TodoMVC.
// To use this, place todomvc directory at the directory containing dojo/dijit/dojox/util (and follow the procedure of building Dojo).
// Refer to todomvc/architecture-examples/dojo/js/lib/dojo-1.8 and todomvc/architecture-examples/dojo/js/lib/dijit-1.8 to see what built files need to be copied.