define([ "dojo/_base/array", "dojo/_base/lang", "dojo/_base/declare", "./_Container", "./at", "./Group", "dijit/form/TextBox" ], function(array, lang, declare, Container, at){ return declare("dojox.mvc.Generate", [Container], { // summary: // A container that generates a view based on the data model its bound to. // // description: // A generate introspects its data binding and creates a view contained in // it that allows displaying the bound data. Child dijits or custom view // components inside it inherit their parent data binding context from it. // _counter: [private] Integer // A count maintained internally to always generate predictable widget // IDs in the view generated by this container. _counter : 0, // defaultWidgetMapping: Object // The mapping of types to a widget class. Set widgetMapping to override this. // _defaultWidgetMapping: {"String" : "dijit/form/TextBox"}, // defaultClassMapping: Object // The mapping of class to use. Set classMapping to override this. // _defaultClassMapping: {"Label" : "generate-label-cell", "String" : "generate-dijit-cell", "Heading" : "generate-heading", "Row" : "row"}, // defaultIdNameMapping: Object // The mapping of id and name to use. Set idNameMapping to override this. A count will be added to the id and name // _defaultIdNameMapping: {"String" : "textbox_t"}, // children: dojo/Stateful // The array of data model that is used to render child nodes. children: null, // _relTargetProp: String // The name of the property that is used by child widgets for relative data binding. _relTargetProp : "children", startup: function(){ this.inherited(arguments); this._setChildrenAttr(this.children); }, ////////////////////// PRIVATE METHODS //////////////////////// _setChildrenAttr: function(/*dojo/Stateful*/ value){ // summary: // Handler for calls to set("children", val). // description: // Sets "ref" property so that child widgets can refer to, and then rebuilds the children. var children = this.children; this._set("children", value); // this.binding is the resolved ref, so not matching with the new value means change in repeat target. if(this.binding != value){ this.set("ref", value); } if(this._started && (!this._builtOnce || children != value)){ this._builtOnce = true; this._buildContained(value); } }, _buildContained: function(/*dojo/Stateful*/ children){ // summary: // Destroy any existing generated view, recreate it from scratch // parse the new contents. // children: dojo/Stateful // The array of child widgets. // tags: // private if(!children){ return; } this._destroyBody(); this._counter = 0; this.srcNodeRef.innerHTML = this._generateBody(children); this._createBody(); }, _generateBody: function(/*dojo/Stateful*/ children, /*Boolean*/ hideHeading){ // summary: // Generate the markup for the view associated with this generate // container. // children: dojo/Stateful // The associated data to generate a view for. // hideHeading: Boolean // Whether the property name should be displayed as a heading. // tags: // private if(children === void 0){ return ""; } var body = []; var isStatefulModel = lang.isFunction(children.toPlainObject); function generateElement(value, prop){ if(isStatefulModel ? (value && lang.isFunction(value.toPlainObject)) : !lang.isFunction(value)){ if(lang.isArray(value)){ body.push(this._generateRepeat(value, prop)); }else if(isStatefulModel ? value.value : ((value == null || {}.toString.call(value) != "[object Object]") && (!(value || {}).set || !(value || {}).watch))){ // TODO: Data types based widgets body.push(this._generateTextBox(prop, isStatefulModel)); }else{ body.push(this._generateGroup(value, prop, hideHeading)); } } } if(lang.isArray(children)){ array.forEach(children, generateElement, this); }else{ for(var s in children){ if(children.hasOwnProperty(s)){ generateElement.call(this, children[s], s); } } } return body.join(""); }, _generateRepeat: function(/*dojox/mvc/StatefulArray*/ children, /*String*/ repeatHeading){ // summary: // Generate a repeating model-bound view. // children: dojox/mvc/StatefulArray // The bound node (a collection/array node) to generate a // repeating UI/view for. // repeatHeading: String // The heading to be used for this portion. // tags: // private var headingClass = (this.classMapping && this.classMapping["Heading"]) ? this.classMapping["Heading"] : this._defaultClassMapping["Heading"]; return '