source: Dev/trunk/src/client/dojox/mvc/Repeat.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 7.8 KB
Line 
1define([
2        "dojo/_base/declare",
3        "dojo/_base/lang",
4        "dojo/_base/sniff",
5        "dojo/_base/window",
6        "dojo/dom",
7        "dojo/dom-construct",
8        "dojo/_base/array",
9        "dojo/query",
10        "dojo/when",
11        "dijit/registry",
12        "./_Container"
13], function(declare, lang, has, win, dom, domconstruct, array, query, when, registry, _Container){
14
15        return declare("dojox.mvc.Repeat", _Container, {
16                // summary:
17                //              A model-bound container which binds to a collection within a data model
18                //              and produces a repeating user-interface from a template for each
19                //              iteration within the collection.
20                //
21                // description:
22                //              A repeat is bound to an intermediate dojo/Stateful node corresponding
23                //              to an array in the data model. Child dijits or custom view components
24                //              inside it inherit their parent data binding context from it.
25
26                // index: Integer
27                //              An index used to track the current iteration when the repeating UI is
28                //              produced. This may be used to parameterize the content in the repeat
29                //              template for the current iteration.
30                //
31                //              For example, consider a collection of search or query results where
32                //              each item contains a "Name" property used to prime the "Results" data
33                //              model. Then, the following CRUD-style UI displays all the names in
34                //              the search results in text boxes where they may be updated or such.
35                //
36                //              |       <div dojoType="dojox/mvc/Repeat" ref="Results">
37                //              |               <div class="row" dojoType="dojox/mvc/Group" ref="${this.index}">
38                //              |                       <label for="nameInput${this.index}">Name:</label>
39                //              |                       <input dojoType="dijit/form/TextBox" id="nameInput${this.index}" ref="'Name'"></input>
40                //              |               </div>
41                //              |       </div>
42                index : 0,
43
44                // useParent: String
45                //              id of the DOM node to use as the parent for the repeating items, similar to useParentId processed a little differently
46                useParent : "",
47               
48                // removeRepeatNode: boolean
49                //              When true the dom node for the Repeat and Groups within the Repeat
50                //              will be removed, their children will be placed into the parent node
51                //              of the Repeat node.  This should be set to true when working with
52                //              a Repeat inside of a dojox.mobile list.         
53                removeRepeatNode : false,
54
55                // children: dojox/mvc/StatefulArray
56                //              The array of data model that is used to render child nodes.
57                children: null,
58
59                // _relTargetProp: String
60                //              The name of the property that is used by child widgets for relative data binding.
61                _relTargetProp : "children",
62
63                startup: function(){
64                        // This code needed for ticket 14423 is using removeRepeatNode to work with mobile.lists
65                        // this.select and this.onCheckStateChanged are called by ListItem so they need to be set
66                        // but it seems like a bit of a hack.
67                        if(this.removeRepeatNode){                             
68                                var parent = null;
69                                if(lang.isFunction(this.getParent)){
70                                        if(this.getParent()){
71                                                this.select = this.getParent().select;
72                                                this.onCheckStateChanged = this.getParent().onCheckStateChanged;
73                                        }
74                                }                       
75                        }
76
77                        this.inherited(arguments);
78                        this._setChildrenAttr(this.children);
79                },
80
81                // summary:
82                //              Override and save template from body.
83                postscript: function(params, srcNodeRef){
84                        //this.srcNodeRef = dom.byId(srcNodeRef);
85                        if(this.useParent && dom.byId(this.useParent)){
86                                this.srcNodeRef = dom.byId(this.useParent);                             
87                        } else{
88                                this.srcNodeRef = dom.byId(srcNodeRef);
89                        }
90                        if(this.srcNodeRef){
91                                var prop = this._attachTemplateNodes ? "inlineTemplateString" : "templateString";
92                                if(this[prop] == ""){ // only overwrite templateString if it has not been set
93                                        this[prop] = this.srcNodeRef.innerHTML;
94                                }
95                                try{
96                                        this.srcNodeRef.innerHTML = "";
97                                }catch(e){
98                                        while(this.srcNodeRef.firstChild){ this.srcNodeRef.removeChild(this.srcNodeRef.firstChild); }
99                                }
100
101                        }
102                        this.inherited(arguments);
103                },
104
105                ////////////////////// PRIVATE METHODS ////////////////////////
106
107                _setChildrenAttr: function(/*dojo/Stateful*/ value){
108                        // summary:
109                        //              Handler for calls to set("children", val).
110                        // description:
111                        //              Sets "ref" property so that child widgets can refer to, and then rebuilds the children.
112
113                        var children = this.children;
114                        this._set("children", value);
115                        // this.binding is the resolved ref, so not matching with the new value means change in repeat target.
116                        if(this.binding != value){
117                                this.set("ref", value);
118                        }
119                        if(this._started && (!this._builtOnce || children != value)){
120                                this._builtOnce = true;
121                                this._buildContained(value);
122                        }
123                },
124
125                _buildContained: function(/*dojox/mvc/StatefulArray*/ children){
126                        // summary:
127                        //              Destroy any existing contained view, recreate the repeating UI
128                        //              markup and parse the new contents.
129                        // children: dojox/mvc/StatefulArray
130                        //              The array of child widgets.
131                        // tags:
132                        //              private
133
134                        if(!children){ return; }
135
136                        // TODO: Potential optimization: only create new widgets for insert, only destroy for delete.
137                        if(this.useParent && dom.byId(this.useParent)){
138                                this.srcNodeRef = dom.byId(this.useParent);                             
139                        }
140
141                        this._destroyBody();
142                        this._updateAddRemoveWatch(children);
143
144                        var insert = [], prop = this._attachTemplateNodes ? "inlineTemplateString" : "templateString";
145                        for(this.index = 0; lang.isFunction(children.get) ? children.get(this.index) : children[this.index]; this.index++){
146                                insert.push(this._exprRepl(this[prop]));
147                        }
148
149                        var repeatNode = this.containerNode || this.srcNodeRef || this.domNode;
150                        if(has("ie") && /^(table|tbody)$/i.test(repeatNode.tagName)){
151                                var div = win.doc.createElement("div");
152                                div.innerHTML = "<table><tbody>" + insert.join("") + "</tbody></table>";
153                                for(var tbody = div.getElementsByTagName("tbody")[0]; tbody.firstChild;){
154                                        repeatNode.appendChild(tbody.firstChild);
155                                }
156                        }else if(has("ie") && /^td$/i.test(repeatNode.tagName)){
157                                var div = win.doc.createElement("div");
158                                div.innerHTML = "<table><tbody><tr>" + insert.join("") + "</tr></tbody></table>";
159                                for(var tr = div.getElementsByTagName("tr")[0]; tr.firstChild;){
160                                        repeatNode.appendChild(tr.firstChild);
161                                }
162                        }else{
163                                repeatNode.innerHTML = insert.join("");
164                        }
165
166                        // srcNodeRef is used in _createBody, so in the programmatic create case where repeatNode was set 
167                        // from this.domNode we need to set srcNodeRef from repeatNode
168                        this.srcNodeRef = repeatNode;
169
170                        var _self = this;
171
172                        when(this._createBody(), function(){
173                                if(!_self.removeRepeatNode){ return; }
174                               
175                                var repeatnode = _self.domNode;
176                                if(!_self.savedParentId && _self.domNode.parentNode && _self.domNode.parentNode.id){
177                                        _self.savedParentId = _self.domNode.parentNode.id;
178                                }
179                                var repeatParent = dom.byId(_self.savedParentId);                       
180                                if(repeatnode && repeatnode.children){
181                                        var t3 = registry.findWidgets(repeatnode);
182                                        var parentcnt = t3.length;
183                                        for(var j = parentcnt;j > 0;j--){
184                                                if(t3[j-1].declaredClass == "dojox.mvc.Group"){
185                                                        var cnt = repeatnode.children[j-1].children.length;
186                                                        var selForList = registry.byId(repeatParent.id).select;
187                                                        for(var i = cnt;i > 0;i--){
188                                                                registry.byId(repeatnode.children[j-1].id).select = selForList;
189                                                                domconstruct.place(repeatnode.children[j-1].removeChild(repeatnode.children[j-1].children[i-1]), repeatParent, "first");
190                                                        }                                                       
191                                                }else{
192                                                        domconstruct.place(repeatnode.removeChild(repeatnode.children[j-1]), repeatParent, "first");                                                   
193                                                }
194                                        }
195                                        domconstruct.destroy(repeatnode);
196                                }
197                        });
198                },
199
200                _updateAddRemoveWatch: function(/*dojo/Stateful*/ children){
201                        // summary:
202                        //              Updates the watch handle when binding changes.
203                        // children: dojo/Stateful
204                        //              The array of child widgets.
205                        // tags:
206                        //              private
207                        if(this._addRemoveWatch){
208                                this._addRemoveWatch.unwatch();
209                        }
210                        var pThis = this;
211                        this._addRemoveWatch = lang.isFunction(children.watchElements) && children.watchElements(function(idx, removals, adds){
212                                if(!removals || !adds || removals.length || adds.length){
213                                        pThis._buildContained(pThis.children);
214                                }
215                        });
216                }
217        });
218});
Note: See TracBrowser for help on using the repository browser.