|
1 | | -/*ko.viewmodel.js - version 2.0.3 |
| 1 | +/*ko.viewmodel.js - version 2.0.3 |
2 | 2 | * Copyright 2013, Dave Herren http://coderenaissance.github.com/knockout.viewmodel/ |
3 | 3 | * License: MIT (http://www.opensource.org/licenses/mit-license.php)*/ |
4 | 4 | /*jshint eqnull:true, boss:true, loopfunc:true, evil:true, laxbreak:true, undef:true, unused:true, browser:true, immed:true, devel:true, sub: true, maxerr:50 */ |
5 | 5 | /*global ko:false */ |
6 | 6 |
|
7 | 7 | (function () { |
8 | 8 | //Module declarations. For increased compression with simple settings on the closure compiler, |
9 | | - //the ko functions are stored in variables. These variable names will be shortened by the compiler, |
| 9 | + //the ko functions are stored in variables. These variable names will be shortened by the compiler, |
10 | 10 | //whereas references to ko would not be. There is also a performance savings from this. |
11 | 11 | var unwrap = ko.utils.unwrapObservable, |
12 | 12 | isObservable = ko.isObservable, |
|
70 | 70 |
|
71 | 71 | //while dates aren't part of the JSON spec it doesn't hurt to support them as it's not unreasonable to think they might be added to the model manually. |
72 | 72 | //undefined is also not part of the spec, but it's currently be supported to be more in line with ko.mapping and probably doesn't hurt. |
73 | | - function isPrimativeOrDate(obj) { |
| 73 | + function isPrimitiveOrDate(obj) { |
74 | 74 | return obj === null || obj === undefined || obj.constructor === String || obj.constructor === Number || obj.constructor === Boolean || obj instanceof Date; |
75 | 75 | } |
76 | 76 |
|
77 | | - function recrusiveFrom(modelObj, settings, context, pathSettings) { |
| 77 | + function recursiveFrom(modelObj, settings, context, pathSettings) { |
78 | 78 | var temp, result, p, length, idName, newContext, customPathSettings, extend, optionProcessed, |
79 | 79 | childPathSettings, childObj; |
80 | 80 | pathSettings = pathSettings || getPathSettings(settings, context); |
81 | 81 |
|
82 | 82 | if (customPathSettings = pathSettings.custom) { |
83 | 83 | optionProcessed = true; |
84 | | - //custom can either be specified as a single map function or as an |
| 84 | + //custom can either be specified as a single map function or as an |
85 | 85 | //object with map and unmap properties |
86 | 86 | if (typeof customPathSettings === "function") { |
87 | 87 | result = customPathSettings(modelObj); |
|
107 | 107 | optionProcessed = true; |
108 | 108 | return badResult; |
109 | 109 | } |
110 | | - else if (isPrimativeOrDate(modelObj)) { |
111 | | - //primative and date children of arrays aren't mapped... all others are |
| 110 | + else if (isPrimitiveOrDate(modelObj)) { |
| 111 | + //primitive and date children of arrays aren't mapped... all others are |
112 | 112 | result = context.parentIsArray ? modelObj : makeObservable(modelObj); |
113 | 113 | } |
114 | 114 | else if (modelObj instanceof Array) { |
115 | 115 | result = []; |
116 | 116 |
|
117 | 117 | for (p = 0, length = modelObj.length; p < length; p++) { |
118 | | - result[p] = recrusiveFrom(modelObj[p], settings, { |
| 118 | + result[p] = recursiveFrom(modelObj[p], settings, { |
119 | 119 | name: "[i]", parent: context.name + "[i]", full: context.full + "[i]", parentIsArray: true |
120 | 120 | }); |
121 | 121 | } |
|
134 | 134 | //wrap array methods for adding and removing items in functions that |
135 | 135 | //close over settings and context allowing the objects and their children to be correctly mapped. |
136 | 136 | result.pushFromModel = function (item) { |
137 | | - item = recrusiveFrom(item, settings, newContext); |
| 137 | + item = recursiveFrom(item, settings, newContext); |
138 | 138 | result.push(item); |
139 | 139 | }; |
140 | 140 | result.unshiftFromModel = function (item) { |
141 | | - item = recrusiveFrom(item, settings, newContext); |
| 141 | + item = recursiveFrom(item, settings, newContext); |
142 | 142 | result.unshift(item); |
143 | 143 | }; |
144 | 144 | result.popToModel = function (item) { |
145 | 145 | item = result.pop(); |
146 | | - return recrusiveTo(item, newContext); |
| 146 | + return recursiveTo(item, newContext); |
147 | 147 | }; |
148 | 148 | result.shiftToModel = function (item) { |
149 | 149 | item = result.shift(); |
150 | | - return recrusiveTo(item, newContext); |
| 150 | + return recursiveTo(item, newContext); |
151 | 151 | }; |
152 | 152 | } |
153 | 153 |
|
|
161 | 161 | full: context.full + "." + p |
162 | 162 | }; |
163 | 163 | childObj = modelObj[p]; |
164 | | - childPathSettings = isPrimativeOrDate(childObj) ? getPathSettings(settings, newContext) : undefined; |
| 164 | + childPathSettings = isPrimitiveOrDate(childObj) ? getPathSettings(settings, newContext) : undefined; |
165 | 165 |
|
166 | 166 | if (childPathSettings && childPathSettings.custom) {//primativish value w/ custom maping |
167 | | - //since primative children cannot store their own custom functions, handle processing here and store them in the parent |
| 167 | + //since primitive children cannot store their own custom functions, handle processing here and store them in the parent |
168 | 168 | result.___$customChildren = result.___$customChildren || {}; |
169 | 169 | result.___$customChildren[p] = childPathSettings.custom; |
170 | 170 |
|
|
176 | 176 | } |
177 | 177 | } |
178 | 178 | else { |
179 | | - temp = recrusiveFrom(childObj, settings, newContext, childPathSettings);//call recursive from on each child property |
| 179 | + temp = recursiveFrom(childObj, settings, newContext, childPathSettings);//call recursive from on each child property |
180 | 180 |
|
181 | 181 | if (temp !== badResult) {//properties that couldn't be mapped return badResult |
182 | 182 | result[p] = temp; |
|
205 | 205 | return result; |
206 | 206 | } |
207 | 207 |
|
208 | | - function recrusiveTo(viewModelObj, context) { |
| 208 | + function recursiveTo(viewModelObj, context) { |
209 | 209 | var result, p, length, temp, unwrapped = unwrap(viewModelObj), child, recursiveResult, |
210 | 210 | wasWrapped = (viewModelObj !== unwrapped);//this works because unwrap observable calls isObservable and returns the object unchanged if not observable |
211 | 211 |
|
|
219 | 219 | else if (viewModelObj && viewModelObj.___$unmapCustom) {//Defer to customUnmapping where specified |
220 | 220 | result = viewModelObj.___$unmapCustom(viewModelObj); |
221 | 221 | } |
222 | | - else if ((wasWrapped && isPrimativeOrDate(unwrapped)) || isNullOrUndefined(unwrapped)) { |
| 222 | + else if ((wasWrapped && isPrimitiveOrDate(unwrapped)) || isNullOrUndefined(unwrapped)) { |
223 | 223 | //return null, undefined, values, and wrapped primativish values as is |
224 | 224 | result = unwrapped; |
225 | 225 | } |
226 | 226 | else if (unwrapped instanceof Array) {//create new array to return and add unwrapped values to it |
227 | 227 | result = []; |
228 | 228 | for (p = 0, length = unwrapped.length; p < length; p++) { |
229 | | - result[p] = recrusiveTo(unwrapped[p], { |
| 229 | + result[p] = recursiveTo(unwrapped[p], { |
230 | 230 | name: "[i]", parent: context.name + "[i]", full: context.full + "[i]" |
231 | 231 | }); |
232 | 232 | } |
|
242 | 242 | child = unwrapped[p]; |
243 | 243 | if (!ko.isComputed(child) && !((temp = unwrap(child)) && temp.constructor === Function)) { |
244 | 244 |
|
245 | | - recursiveResult = recrusiveTo(child, { |
| 245 | + recursiveResult = recursiveTo(child, { |
246 | 246 | name: p, |
247 | 247 | parent: (context.name === "[i]" ? context.parent : context.name) + "." + p, |
248 | 248 | full: context.full + "." + p |
|
271 | 271 | return result; |
272 | 272 | } |
273 | 273 |
|
274 | | - function recursiveUpdate(modelObj, viewModelObj, context, parentObj, noncontiguousObjectUpdateCount) { |
| 274 | + function recursiveUpdate(modelObj, viewModelObj, context, parentObj, nonContiguousObjectUpdateCount) { |
275 | 275 | var p, q, foundModels, foundViewmodels, modelId, viewmodelId, idName, length, unwrapped = unwrap(viewModelObj), |
276 | 276 | wasWrapped = (viewModelObj !== unwrapped), child, map, tempArray, childTemp, childMap, unwrappedChild, tempChild; |
277 | 277 |
|
|
280 | 280 | } |
281 | 281 |
|
282 | 282 | if (wasWrapped && (isNullOrUndefined(unwrapped) ^ isNullOrUndefined(modelObj))) { |
283 | | - //if you have an observable to update and either the new or old value is |
| 283 | + //if you have an observable to update and either the new or old value is |
284 | 284 | //null or undefined then update the observable |
285 | 285 | viewModelObj(modelObj); |
286 | 286 | } |
|
294 | 294 | else { |
295 | 295 | child = unwrapped[p]; |
296 | 296 |
|
297 | | - if (!wasWrapped && unwrapped.hasOwnProperty(p) && (isPrimativeOrDate(child) || (child && child.constructor === Array))) { |
| 297 | + if (!wasWrapped && unwrapped.hasOwnProperty(p) && (isPrimitiveOrDate(child) || (child && child.constructor === Array))) { |
298 | 298 | unwrapped[p] = modelObj[p]; |
299 | 299 | } |
300 | 300 | else if (child && typeof child.___$mapCustom === "function") { |
|
314 | 314 | unwrapped[p] = modelObj[p]; |
315 | 315 | } |
316 | 316 | else {//Recursive update everything else |
317 | | - if (!!noncontiguousObjectUpdateCount) { |
| 317 | + if (!!nonContiguousObjectUpdateCount) { |
318 | 318 | var fnRecursivePropertyObjectUpdate = (function (modelObj, viewModelObj, p) { |
319 | 319 | return function () {//keep in sync with else below |
320 | 320 | recursiveUpdate(modelObj[p], unwrapped[p], { |
321 | 321 | name: p, |
322 | 322 | parent: (context.name === "[i]" ? context.parent : context.name) + "." + p, |
323 | 323 | full: context.full + "." + p |
324 | | - }, unwrapped, noncontiguousObjectUpdateCount); |
325 | | - noncontiguousObjectUpdateCount(noncontiguousObjectUpdateCount() - 1); |
| 324 | + }, unwrapped, nonContiguousObjectUpdateCount); |
| 325 | + nonContiguousObjectUpdateCount(nonContiguousObjectUpdateCount() - 1); |
326 | 326 | }; |
327 | 327 | }(modelObj, viewModelObj, p)); |
328 | | - noncontiguousObjectUpdateCount(noncontiguousObjectUpdateCount() + 1); |
| 328 | + nonContiguousObjectUpdateCount(nonContiguousObjectUpdateCount() + 1); |
329 | 329 | setTimeout(fnRecursivePropertyObjectUpdate, 0); |
330 | 330 | } |
331 | 331 | else {//keep in sync with if above |
|
358 | 358 | child(unwrap(tempChild)); |
359 | 359 | } |
360 | 360 | //else custom mapping returned previous observable; |
361 | | - //if it's smart enough to do that, assume it updated it correctly |
| 361 | + //if it's smart enough to do that, assume it updated it correctly |
362 | 362 | } |
363 | 363 | else { |
364 | 364 | unwrapped[q] = child.___$mapCustom(modelObj[p], child); |
365 | 365 | } |
366 | 366 | } |
367 | 367 | else { |
368 | | - |
369 | | - if (!!noncontiguousObjectUpdateCount) {//keep in sync with else block below |
| 368 | + |
| 369 | + if (!!nonContiguousObjectUpdateCount) {//keep in sync with else block below |
370 | 370 | var fnRecursiveArrayChildObjectUpdate = (function (modelObj, viewModelObj, p, q) { |
371 | 371 | return function () { |
372 | 372 | recursiveUpdate(modelObj[p], unwrapped[q], { |
373 | 373 | name: "[i]", parent: context.name + "[i]", full: context.full + "[i]" |
374 | | - }, undefined, noncontiguousObjectUpdateCount); |
| 374 | + }, undefined, nonContiguousObjectUpdateCount); |
375 | 375 |
|
376 | | - noncontiguousObjectUpdateCount(noncontiguousObjectUpdateCount() - 1); |
| 376 | + nonContiguousObjectUpdateCount(nonContiguousObjectUpdateCount() - 1); |
377 | 377 | }; |
378 | 378 | }(modelObj, viewModelObj, p, q)); |
379 | | - noncontiguousObjectUpdateCount(noncontiguousObjectUpdateCount() + 1); |
| 379 | + nonContiguousObjectUpdateCount(nonContiguousObjectUpdateCount() + 1); |
380 | 380 | setTimeout(fnRecursiveArrayChildObjectUpdate, 0); |
381 | 381 | } |
382 | 382 | else {//keep in sync with if block above |
|
423 | 423 | viewModelObj(modelObj); |
424 | 424 | } |
425 | 425 |
|
426 | | - if (context.name === "{root}" && !!noncontiguousObjectUpdateCount) { |
| 426 | + if (context.name === "{root}" && !!nonContiguousObjectUpdateCount) { |
427 | 427 | return { |
428 | 428 | onComplete:function (fnOnComplete) { |
429 | 429 | if(fnOnComplete && typeof fnOnComplete == "function"){ |
430 | | - if (!!noncontiguousObjectUpdateCount) { |
| 430 | + if (!!nonContiguousObjectUpdateCount) { |
431 | 431 | ko.computed(function () { |
432 | | - if (fnOnComplete && noncontiguousObjectUpdateCount() === 0) { |
| 432 | + if (fnOnComplete && nonContiguousObjectUpdateCount() === 0) { |
433 | 433 | fnOnComplete(); |
434 | 434 | fnOnComplete = undefined; |
435 | 435 | } |
|
479 | 479 | fromModel: function fnFromModel(model, options) { |
480 | 480 | var settings = getPathSettingsDictionary(options); |
481 | 481 | initInternals(this.options, "Mapping From Model"); |
482 | | - return recrusiveFrom(model, settings, rootContext); |
| 482 | + return recursiveFrom(model, settings, rootContext); |
483 | 483 | }, |
484 | 484 | toModel: function fnToModel(viewmodel) { |
485 | 485 | initInternals(this.options, "Mapping To Model"); |
486 | | - return recrusiveTo(viewmodel, rootContext); |
| 486 | + return recursiveTo(viewmodel, rootContext); |
487 | 487 | }, |
488 | | - updateFromModel: function fnUpdateFromModel(viewmodel, model, makeNoncontiguousObjectUpdates) { |
489 | | - var noncontiguousObjectUpdateCount = makeNoncontiguousObjectUpdates ? ko.observable(0) : undefined; |
| 488 | + updateFromModel: function fnUpdateFromModel(viewmodel, model, makeNonContiguousObjectUpdates) { |
| 489 | + var nonContiguousObjectUpdateCount = makeNonContiguousObjectUpdates ? ko.observable(0) : undefined; |
490 | 490 | initInternals(this.options, "Update From Model"); |
491 | | - return recursiveUpdate(model, viewmodel, rootContext, undefined, noncontiguousObjectUpdateCount); |
| 491 | + return recursiveUpdate(model, viewmodel, rootContext, undefined, nonContiguousObjectUpdateCount); |
492 | 492 | } |
493 | 493 | }; |
494 | 494 | }()); |
0 commit comments