]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * This class is created to manage a multi-bind against a `ViewModel`.\r | |
3 | */\r | |
4 | Ext.define('Ext.app.bind.Multi', {\r | |
5 | extend: 'Ext.app.bind.BaseBinding',\r | |
6 | \r | |
7 | isMultiBinding: true,\r | |
8 | \r | |
9 | missing: 1,\r | |
10 | \r | |
11 | // Multi binds have to be deep. We construct a single object/array and we only\r | |
12 | // ever fire by notifying with that value which will never change. As such, we\r | |
13 | // need to notify any child bindings so they can check if their individual\r | |
14 | // bindings have changed.\r | |
15 | deep: true,\r | |
16 | \r | |
17 | /**\r | |
18 | * @cfg {Boolean} trackStatics\r | |
19 | * This option tracks for static branches of the root object which can be pruned using\r | |
20 | * {@link #pruneStaticKeys}. This can be useful to only get the dynamic parts of a multi bind:\r | |
21 | *\r | |
22 | * {\r | |
23 | * a: 1,\r | |
24 | * b: '{someBind}',\r | |
25 | * c: ['a', 'b', 'c'],\r | |
26 | * d: ['a', 'b', '{someBind}'],\r | |
27 | * e: {\r | |
28 | * y: 1,\r | |
29 | * z: 2\r | |
30 | * },\r | |
31 | * f: {\r | |
32 | * y: 1,\r | |
33 | * z: '{someBind}'\r | |
34 | * }\r | |
35 | * }\r | |
36 | *\r | |
37 | * // Will produce\r | |
38 | * {\r | |
39 | * b: value,\r | |
40 | * d: ['a', 'b', value],\r | |
41 | * f: {\r | |
42 | * y: 1,\r | |
43 | * z: value\r | |
44 | * }\r | |
45 | * }\r | |
46 | * @private\r | |
47 | * @since 5.1.0\r | |
48 | */\r | |
49 | \r | |
50 | constructor: function (descriptor, owner, callback, scope, options) {\r | |
51 | var me = this,\r | |
52 | trackStatics = options && options.trackStatics;\r | |
53 | \r | |
54 | me.callParent([ owner, callback, scope, options ]);\r | |
55 | \r | |
56 | me.bindings = [];\r | |
57 | me.literal = descriptor.$literal;\r | |
58 | \r | |
59 | if (descriptor.constructor === Object) {\r | |
60 | if (trackStatics) {\r | |
61 | me.staticKeys = [];\r | |
62 | }\r | |
63 | me.addObject(descriptor, me.lastValue = {}, me.staticKeys);\r | |
64 | } else {\r | |
65 | me.addArray(descriptor, me.lastValue = []);\r | |
66 | }\r | |
67 | \r | |
68 | // We started at missing == 1 so that no immediate callbacks would hit 0 before\r | |
69 | // adding all bindings... so now we decrement by 1 to balance things and see if\r | |
70 | // we are at 0.\r | |
71 | if (! --me.missing && !me.scheduled) {\r | |
72 | me.schedule();\r | |
73 | }\r | |
74 | },\r | |
75 | \r | |
76 | destroy: function () {\r | |
77 | var me = this;\r | |
78 | \r | |
79 | me.bindings = Ext.destroy(me.bindings);\r | |
80 | \r | |
81 | me.callParent();\r | |
82 | },\r | |
83 | \r | |
84 | add: function (descriptor, data, property) {\r | |
85 | var me = this,\r | |
86 | owner = me.owner,\r | |
87 | bindings = me.bindings,\r | |
88 | method = me.literal ? (descriptor.reference ? 'bindEntity' : 'bindExpression')\r | |
89 | : 'bind',\r | |
90 | binding, depth;\r | |
91 | \r | |
92 | ++me.missing;\r | |
93 | \r | |
94 | binding = owner[method](descriptor,\r | |
95 | function (value) {\r | |
96 | data[property] = value;\r | |
97 | \r | |
98 | if (binding.calls === 1) {\r | |
99 | --me.missing;\r | |
100 | }\r | |
101 | \r | |
102 | if (!me.missing && !me.scheduled) {\r | |
103 | me.schedule();\r | |
104 | }\r | |
105 | },\r | |
106 | //TODO - split bind options between us and the sub-binds (pass null for now)\r | |
107 | me, null);\r | |
108 | \r | |
109 | depth = binding.depth;\r | |
110 | if (!bindings.length || depth < me.depth) {\r | |
111 | me.depth = depth;\r | |
112 | }\r | |
113 | \r | |
114 | bindings.push(binding);\r | |
115 | return !this.isBindingStatic(binding);\r | |
116 | },\r | |
117 | \r | |
118 | addArray: function (multiBindDescr, array) {\r | |
119 | var me = this,\r | |
120 | n = multiBindDescr.length,\r | |
121 | hasDynamic = false,\r | |
122 | dynamic, b, i;\r | |
123 | \r | |
124 | for (i = 0; i < n; ++i) {\r | |
125 | b = multiBindDescr[i];\r | |
126 | \r | |
127 | if (b && (b.reference || Ext.isString(b))) {\r | |
128 | dynamic = me.add(b, array, i);\r | |
129 | } else if (Ext.isArray(b)) {\r | |
130 | dynamic = me.addArray(b, array[i] = []);\r | |
131 | } else if (b && b.constructor === Object) {\r | |
132 | dynamic = me.addObject(b, array[i] = {});\r | |
133 | } else {\r | |
134 | array[i] = b;\r | |
135 | dynamic = false;\r | |
136 | }\r | |
137 | hasDynamic = hasDynamic || dynamic;\r | |
138 | }\r | |
139 | return hasDynamic;\r | |
140 | },\r | |
141 | \r | |
142 | addObject: function (multiBindDescr, object, staticKeys) {\r | |
143 | var me = this,\r | |
144 | hasDynamic = false,\r | |
145 | dynamic, b, name;\r | |
146 | \r | |
147 | for (name in multiBindDescr) {\r | |
148 | b = multiBindDescr[name];\r | |
149 | \r | |
150 | if (b && (b.reference || Ext.isString(b))) {\r | |
151 | dynamic = me.add(b, object, name);\r | |
152 | } else if (Ext.isArray(b)) {\r | |
153 | dynamic = me.addArray(b, object[name] = []);\r | |
154 | } else if (b && b.constructor === Object) {\r | |
155 | dynamic = me.addObject(b, object[name] = {});\r | |
156 | } else {\r | |
157 | object[name] = b;\r | |
158 | dynamic = false;\r | |
159 | }\r | |
160 | if (staticKeys && !dynamic) {\r | |
161 | staticKeys.push(name);\r | |
162 | }\r | |
163 | hasDynamic = hasDynamic || dynamic;\r | |
164 | }\r | |
165 | return hasDynamic;\r | |
166 | },\r | |
167 | \r | |
168 | getFullName: function () {\r | |
169 | var me = this,\r | |
170 | fullName = me.fullName,\r | |
171 | bindings = me.bindings,\r | |
172 | length = bindings.length,\r | |
173 | i;\r | |
174 | \r | |
175 | if (!fullName) {\r | |
176 | fullName = '@[';\r | |
177 | for (i = 0; i < length; ++i) {\r | |
178 | if (i) {\r | |
179 | fullName += ',';\r | |
180 | }\r | |
181 | fullName += bindings[i].getFullName();\r | |
182 | }\r | |
183 | fullName += ']';\r | |
184 | \r | |
185 | me.fullName = fullName;\r | |
186 | }\r | |
187 | \r | |
188 | return fullName;\r | |
189 | },\r | |
190 | \r | |
191 | getRawValue: function () {\r | |
192 | return this.lastValue;\r | |
193 | },\r | |
194 | \r | |
195 | isDescendantOf: function () {\r | |
196 | return false;\r | |
197 | },\r | |
198 | \r | |
199 | isLoading: function () {\r | |
200 | for (var bindings = this.bindings, n = bindings.length; n-- > 0; ) {\r | |
201 | if (bindings[n].isLoading()) {\r | |
202 | return true;\r | |
203 | }\r | |
204 | }\r | |
205 | \r | |
206 | return false;\r | |
207 | },\r | |
208 | \r | |
209 | isBindingStatic: function(binding) {\r | |
210 | return binding.isTemplateBinding && binding.isStatic;\r | |
211 | },\r | |
212 | \r | |
213 | isStatic: function() {\r | |
214 | var bindings = this.bindings,\r | |
215 | len = bindings.length,\r | |
216 | i, binding;\r | |
217 | \r | |
218 | for (i = 0; i < len; ++i) {\r | |
219 | binding = bindings[i];\r | |
220 | if (!this.isBindingStatic(binding)) {\r | |
221 | return false;\r | |
222 | }\r | |
223 | }\r | |
224 | return true;\r | |
225 | },\r | |
226 | \r | |
227 | pruneStaticKeys: function() {\r | |
228 | var value = Ext.apply({}, this.lastValue),\r | |
229 | keys = this.staticKeys,\r | |
230 | len = keys.length,\r | |
231 | i;\r | |
232 | \r | |
233 | for (i = 0; i < len; ++i) {\r | |
234 | delete value[keys[i]];\r | |
235 | }\r | |
236 | return value;\r | |
237 | },\r | |
238 | \r | |
239 | react: function () {\r | |
240 | this.notify(this.lastValue);\r | |
241 | },\r | |
242 | \r | |
243 | refresh: function () {\r | |
244 | // @TODO\r | |
245 | },\r | |
246 | \r | |
247 | privates: {\r | |
248 | sort: function () {\r | |
249 | this.scheduler.sortItems(this.bindings);\r | |
250 | \r | |
251 | // Schedulable#sort === emptyFn\r | |
252 | //me.callParent();\r | |
253 | }\r | |
254 | }\r | |
255 | });\r |