]> git.proxmox.com Git - extjs.git/blame - extjs/examples/classic/neptune-components/.sencha/app/Microloader.js
add extjs 6.0.1 sources
[extjs.git] / extjs / examples / classic / neptune-components / .sencha / app / Microloader.js
CommitLineData
6527f429
DM
1// here, the extra check for window['Ext'] is needed for use with cmd-test\r
2// code injection. we need to make that this file will sync up with page global\r
3// scope to avoid duplicate Ext.Boot state. That check is after the initial Ext check\r
4// to allow the sandboxing template to inject an appropriate Ext var and prevent the\r
5// global detection.\r
6var Ext = Ext || window['Ext'] || {};\r
7\r
8\r
9//<editor-fold desc="Microloader">\r
10/**\r
11 * @Class Ext.Microloader\r
12 * @singleton\r
13 */\r
14Ext.Microloader = Ext.Microloader || (function () {\r
15 var Boot = Ext.Boot,\r
16 //<debug>\r
17 _debug = function (message) {\r
18 //console.log(message);\r
19 },\r
20 //</debug>\r
21 _warn = function (message) {\r
22 console.log("[WARN] " + message);\r
23 },\r
24 _privatePrefix = '_sencha',\r
25 _location = window.document.location,\r
26 _documentUri = _location.protocol + '//' + _location.hostname + _location.pathname + _location.search,\r
27 postProcessor;\r
28\r
29 // Returns a unique key to a manifest file\r
30 function getManifestStorageKey (url) {\r
31 return _privatePrefix + '-' + _documentUri + url;\r
32 }\r
33\r
34 var _storage;\r
35 try {\r
36 _storage = window['localStorage'];\r
37 } catch(ex) {\r
38 // ignore\r
39 }\r
40\r
41 var _cache = window['applicationCache'],\r
42 // Local Storage Controller\r
43 LocalStorage = {\r
44 clearAllPrivate: function() {\r
45 if(_storage) {\r
46 var i, key,\r
47 removeKeys = [],\r
48 ln = _storage.length;\r
49 for (i = 0; i < ln; i++) {\r
50 key = _storage.key(i);\r
51 if (key.indexOf(_privatePrefix) === 0) {\r
52 removeKeys.push(key);\r
53 }\r
54 }\r
55\r
56 for(i in removeKeys) {\r
57 //<debug>\r
58 _debug("Removing "+ removeKeys[i] + " from Local Storage");\r
59 //</debug>\r
60 _storage.removeItem(removeKeys[i]);\r
61 }\r
62 }\r
63 },\r
64 /**\r
65 * private\r
66 */\r
67 retrieveAsset: function (key) {\r
68 try {\r
69 return _storage.getItem(key);\r
70 }\r
71 catch (e) {\r
72 // Private browsing mode\r
73 return null;\r
74 }\r
75 },\r
76\r
77 setAsset: function(key, content) {\r
78 try {\r
79 if (content === null || content == '') {\r
80 _storage.removeItem(key);\r
81 } else {\r
82 _storage.setItem(key, content);\r
83 }\r
84 }\r
85 catch (e) {\r
86 if (_storage && e.code == e.QUOTA_EXCEEDED_ERR) {\r
87 //<debug>\r
88 _warn("LocalStorage Quota exceeded, cannot store " + key + " locally");\r
89 //</debug>\r
90 }\r
91 }\r
92 }\r
93 };\r
94\r
95 var Asset = function (cfg) {\r
96 if (typeof cfg.assetConfig === 'string') {\r
97 this.assetConfig = {\r
98 path: cfg.assetConfig\r
99 };\r
100 } else {\r
101 this.assetConfig = cfg.assetConfig;\r
102 }\r
103\r
104 this.type = cfg.type;\r
105 this.key = cfg.manifestKey + '-' + this.assetConfig.path;\r
106\r
107 if (cfg.loadFromCache) {\r
108 this.loadFromCache();\r
109 }\r
110 };\r
111\r
112 Asset.prototype = {\r
113 shouldCache: function() {\r
114 return _storage && this.assetConfig.update && this.assetConfig.hash && !this.assetConfig.remote;\r
115 },\r
116 \r
117 is: function (asset) {\r
118 return (!!asset && this.assetConfig && asset.assetConfig && (this.assetConfig.hash === asset.assetConfig.hash))\r
119 },\r
120\r
121 cache: function(content) {\r
122 if (this.shouldCache()) {\r
123 LocalStorage.setAsset(this.key, content || this.content);\r
124 }\r
125 },\r
126\r
127 uncache: function() {\r
128 LocalStorage.setAsset(this.key, null);\r
129 },\r
130\r
131 updateContent: function (content) {\r
132 this.content = content;\r
133 },\r
134\r
135 getSize: function () {\r
136 return this.content ? this.content.length : 0;\r
137 },\r
138\r
139 loadFromCache: function() {\r
140 if (this.shouldCache()) {\r
141 this.content = LocalStorage.retrieveAsset(this.key);\r
142 }\r
143 }\r
144 };\r
145\r
146 var Manifest = function (cfg) {\r
147 if (typeof cfg.content === "string") {\r
148 this.content = JSON.parse(cfg.content);\r
149 } else {\r
150 this.content = cfg.content;\r
151 }\r
152 this.assetMap = {};\r
153 \r
154 this.url = cfg.url;\r
155 this.fromCache = !!cfg.cached;\r
156 this.assetCache = !(cfg.assetCache === false);\r
157 this.key = getManifestStorageKey(this.url);\r
158\r
159 // Pull out select properties for repetitive use\r
160 this.hash = this.content.hash;\r
161 this.loadOrder = this.content.loadOrder;\r
162 this.deltas = this.content.cache ? this.content.cache.deltas : null;\r
163 this.cacheEnabled = this.content.cache ? this.content.cache.enable : false;\r
164 \r
165 this.loadOrderMap = (this.loadOrder) ? Boot.createLoadOrderMap(this.loadOrder) : null;\r
166 \r
167 // Convert all assets into Assets\r
168 this.js = this.processAssets(this.content.js, 'js');\r
169 this.css = this.processAssets(this.content.css, 'css');\r
170 };\r
171\r
172 Manifest.prototype = {\r
173 processAsset: function(assetConfig, type) {\r
174 var processedAsset = new Asset({\r
175 manifestKey: this.key,\r
176 assetConfig: assetConfig,\r
177 type: type,\r
178 loadFromCache: this.assetCache\r
179 });\r
180 this.assetMap[assetConfig.path] = processedAsset;\r
181 return processedAsset;\r
182 },\r
183\r
184 processAssets: function(assets, type) {\r
185 var results = [],\r
186 ln = assets.length,\r
187 i, assetConfig;\r
188\r
189 for (i = 0; i < ln; i++) {\r
190 assetConfig = assets[i];\r
191 results.push(this.processAsset(assetConfig, type));\r
192 }\r
193\r
194 return results;\r
195 },\r
196\r
197 useAppCache: function() {\r
198 return true;\r
199 },\r
200\r
201 // Concatenate all assets for easy access\r
202 getAssets: function () {\r
203 return this.css.concat(this.js);\r
204 },\r
205\r
206 getAsset: function (path) {\r
207 return this.assetMap[path];\r
208 },\r
209\r
210 shouldCache: function() {\r
211 return this.hash && this.cacheEnabled;\r
212 },\r
213\r
214 cache: function(content) {\r
215 if (this.shouldCache()) {\r
216 LocalStorage.setAsset(this.key, JSON.stringify(content || this.content));\r
217 }\r
218 //<debug>\r
219 else {\r
220 _debug("Manifest caching is disabled.");\r
221 }\r
222 //</debug>\r
223 },\r
224\r
225 is: function(manifest) {\r
226 //<debug>\r
227 _debug("Testing Manifest: " + this.hash + " VS " + manifest.hash);\r
228 //</debug>\r
229 return this.hash === manifest.hash;\r
230 },\r
231\r
232 // Clear the manifest from local storage\r
233 uncache: function() {\r
234 LocalStorage.setAsset(this.key, null);\r
235 },\r
236 \r
237 exportContent: function() {\r
238 return Boot.apply({\r
239 loadOrderMap: this.loadOrderMap\r
240 }, this.content);\r
241 }\r
242 };\r
243\r
244 /**\r
245 * Microloader\r
246 * @type {Array}\r
247 * @private\r
248 */\r
249 var _listeners = [],\r
250 _loaded = false,\r
251 Microloader = {\r
252 init: function () {\r
253 Ext.microloaded = true;\r
254 if (Ext.beforeLoad) {\r
255 postProcessor = Ext.beforeLoad(Ext.platformTags);\r
256 }\r
257\r
258 var readyHandler = Ext._beforereadyhandler;\r
259\r
260 Ext._beforereadyhandler = function () {\r
261 if (Ext.Boot !== Boot) {\r
262 Ext.apply(Ext.Boot, Boot);\r
263 Ext.Boot = Boot;\r
264 }\r
265 if (readyHandler) {\r
266 readyHandler();\r
267 }\r
268 };\r
269 },\r
270\r
271 run: function() {\r
272 Microloader.init();\r
273 var manifest = Ext.manifest;\r
274\r
275 if (typeof manifest === "string") {\r
276 var extension = ".json",\r
277 url = manifest.indexOf(extension) === manifest.length - extension.length\r
278 ? manifest\r
279 : manifest + ".json",\r
280 key = getManifestStorageKey(url),\r
281 content = LocalStorage.retrieveAsset(key);\r
282\r
283 // Manifest found in local storage, use this for immediate boot except in PhantomJS environments for building.\r
284 if (content) {\r
285 //<debug>\r
286 _debug("Manifest file, '" + url + "', was found in Local Storage");\r
287 //</debug>\r
288 manifest = new Manifest({\r
289 url: url,\r
290 content: content,\r
291 cached: true\r
292 });\r
293 if (postProcessor) {\r
294 postProcessor(manifest);\r
295 }\r
296 Microloader.load(manifest);\r
297\r
298\r
299 // Manifest is not in local storage. Fetch it from the server\r
300 } else {\r
301 Boot.fetch(url, function (result) {\r
302 //<debug>\r
303 _debug("Manifest file was not found in Local Storage, loading: " + url);\r
304 //</debug>\r
305 manifest = new Manifest({\r
306 url: url,\r
307 content: result.content\r
308 });\r
309\r
310 manifest.cache();\r
311 if (postProcessor) {\r
312 postProcessor(manifest);\r
313 }\r
314 Microloader.load(manifest);\r
315 });\r
316 }\r
317\r
318 // Embedded Manifest into JS file\r
319 } else {\r
320 //<debug>\r
321 _debug("Manifest was embedded into application javascript file");\r
322 //</debug>\r
323 manifest = new Manifest({\r
324 content: manifest,\r
325 url: 'embedded'\r
326 });\r
327 Microloader.load(manifest);\r
328 }\r
329 },\r
330\r
331 /**\r
332 *\r
333 * @param {Manifest} manifest\r
334 */\r
335 load: function (manifest) {\r
336 Microloader.urls = [];\r
337 Microloader.manifest = manifest;\r
338 Ext.manifest = Microloader.manifest.exportContent();\r
339\r
340 var assets = manifest.getAssets(),\r
341 cachedAssets = [],\r
342 asset, i, len, include, entry;\r
343\r
344 for (len = assets.length, i = 0; i < len; i++) {\r
345 asset = assets[i];\r
346 include = true;\r
347 if (asset.assetConfig.platform && !Boot.filterPlatform(asset.assetConfig.platform)) {\r
348 include = false;\r
349 }\r
350 if (include) {\r
351 // Asset is using the localStorage caching system\r
352 if (manifest.shouldCache() && asset.shouldCache()) {\r
353 // Asset already has content from localStorage, instantly seed that into boot\r
354 if (asset.content) {\r
355 //<debug>\r
356 _debug("Asset: " + asset.assetConfig.path + " was found in local storage. No remote load for this file");\r
357 //</debug>\r
358 entry = Boot.registerContent(asset.assetConfig.path, asset.type, asset.content);\r
359 if (entry.evaluated) {\r
360 _warn("Asset: " + asset.assetConfig.path + " was evaluated prior to local storage being consulted.");\r
361 }\r
362 //load via AJAX and seed content into Boot\r
363 } else {\r
364 //<debug>\r
365 _debug("Asset: " + asset.assetConfig.path + " was NOT found in local storage. Adding to load queue");\r
366 //</debug>\r
367 cachedAssets.push(asset);\r
368 }\r
369 }\r
370 Microloader.urls.push(asset.assetConfig.path);\r
371 }\r
372 }\r
373\r
374 // If any assets are using the caching system and do not have local versions load them first via AJAX\r
375 if (cachedAssets.length > 0) {\r
376 Microloader.remainingCachedAssets = cachedAssets.length;\r
377 while (cachedAssets.length > 0) {\r
378 asset = cachedAssets.pop();\r
379 //<debug>\r
380 _debug("Preloading/Fetching Cached Assets from: " + asset.assetConfig.path);\r
381 //</debug>\r
382 Boot.fetch(asset.assetConfig.path, (function(asset) {\r
383 return function(result) {\r
384 Microloader.onCachedAssetLoaded(asset, result);\r
385 }\r
386 })(asset));\r
387 }\r
388 } else {\r
389 Microloader.onCachedAssetsReady();\r
390 }\r
391 },\r
392\r
393 // Load the asset and seed its content into Boot to be evaluated in sequence\r
394 onCachedAssetLoaded: function (asset, result) {\r
395 var checksum;\r
396 result = Microloader.parseResult(result);\r
397 Microloader.remainingCachedAssets--;\r
398\r
399 if (!result.error) {\r
400 checksum = Microloader.checksum(asset.assetConfig.hash, result.content);\r
401 if (!checksum) {\r
402 _warn("Cached Asset '" + asset.assetConfig.path + "' has failed checksum. This asset will be uncached for future loading");\r
403\r
404 // Un cache this asset so it is loaded next time\r
405 asset.uncache();\r
406 }\r
407\r
408 //<debug>\r
409 _debug("Checksum for Cached Asset: " + asset.assetConfig.path + " is " + checksum);\r
410 //</debug>\r
411 Boot.registerContent(asset.assetConfig.path, asset.type, result.content);\r
412 asset.updateContent(result.content);\r
413 asset.cache();\r
414 } else {\r
415 _warn("There was an error pre-loading the asset '" + asset.assetConfig.path + "'. This asset will be uncached for future loading");\r
416 \r
417 // Un cache this asset so it is loaded next time\r
418 asset.uncache();\r
419 } \r
420 \r
421 if (Microloader.remainingCachedAssets === 0) {\r
422 Microloader.onCachedAssetsReady();\r
423 }\r
424 },\r
425\r
426 onCachedAssetsReady: function(){\r
427 Boot.load({\r
428 url: Microloader.urls,\r
429 loadOrder: Microloader.manifest.loadOrder,\r
430 loadOrderMap: Microloader.manifest.loadOrderMap,\r
431 sequential: true,\r
432 success: Microloader.onAllAssetsReady,\r
433 failure: Microloader.onAllAssetsReady\r
434 });\r
435 },\r
436\r
437 onAllAssetsReady: function() {\r
438 _loaded = true;\r
439 Microloader.notify();\r
440\r
441 if (navigator.onLine !== false) {\r
442 //<debug>\r
443 _debug("Application is online, checking for updates");\r
444 //</debug>\r
445 Microloader.checkAllUpdates();\r
446 }\r
447 else {\r
448 //<debug>\r
449 _debug("Application is offline, adding online listener to check for updates");\r
450 //</debug>\r
451 if(window['addEventListener']) {\r
452 window.addEventListener('online', Microloader.checkAllUpdates, false);\r
453 }\r
454 }\r
455 },\r
456\r
457 onMicroloaderReady: function (listener) {\r
458 if (_loaded) {\r
459 listener();\r
460 } else {\r
461 _listeners.push(listener);\r
462 }\r
463 },\r
464\r
465 /**\r
466 * @private\r
467 */\r
468 notify: function () {\r
469 //<debug>\r
470 _debug("notifying microloader ready listeners.");\r
471 //</debug>\r
472 var listener;\r
473 while((listener = _listeners.shift())) {\r
474 listener();\r
475 }\r
476 },\r
477\r
478 // Delta patches content\r
479 patch: function (content, delta) {\r
480 var output = [],\r
481 chunk, i, ln;\r
482\r
483 if (delta.length === 0) {\r
484 return content;\r
485 }\r
486\r
487 for (i = 0,ln = delta.length; i < ln; i++) {\r
488 chunk = delta[i];\r
489\r
490 if (typeof chunk === 'number') {\r
491 output.push(content.substring(chunk, chunk + delta[++i]));\r
492 }\r
493 else {\r
494 output.push(chunk);\r
495 }\r
496 }\r
497\r
498 return output.join('');\r
499 },\r
500 \r
501 checkAllUpdates: function() {\r
502 //<debug>\r
503 _debug("Checking for All Updates");\r
504 //</debug>\r
505 if(window['removeEventListener']) {\r
506 window.removeEventListener('online', Microloader.checkAllUpdates, false);\r
507 }\r
508\r
509 if(_cache) {\r
510 Microloader.checkForAppCacheUpdate();\r
511 }\r
512\r
513 // Manifest came from a cached instance, check for updates\r
514 if (Microloader.manifest.fromCache) {\r
515 Microloader.checkForUpdates();\r
516 }\r
517 },\r
518\r
519 checkForAppCacheUpdate: function() {\r
520 //<debug>\r
521 _debug("Checking App Cache status");\r
522 //</debug>\r
523 if (_cache.status === _cache.UPDATEREADY || _cache.status === _cache.OBSOLETE) {\r
524 //<debug>\r
525 _debug("App Cache is already in an updated");\r
526 //</debug>\r
527 Microloader.appCacheState = 'updated';\r
528 } else if (_cache.status !== _cache.IDLE && _cache.status !== _cache.UNCACHED) {\r
529 //<debug>\r
530 _debug("App Cache is checking or downloading updates, adding listeners");\r
531 //</debug>\r
532 Microloader.appCacheState = 'checking';\r
533 _cache.addEventListener('error', Microloader.onAppCacheError);\r
534 _cache.addEventListener('noupdate', Microloader.onAppCacheNotUpdated);\r
535 _cache.addEventListener('cached', Microloader.onAppCacheNotUpdated);\r
536 _cache.addEventListener('updateready', Microloader.onAppCacheReady);\r
537 _cache.addEventListener('obsolete', Microloader.onAppCacheObsolete);\r
538 } else {\r
539 //<debug>\r
540 _debug("App Cache is current or uncached");\r
541 //</debug>\r
542 Microloader.appCacheState = 'current';\r
543 }\r
544 },\r
545\r
546 checkForUpdates: function() {\r
547 // Fetch the Latest Manifest from the server\r
548 //<debug>\r
549 _debug("Checking for updates at: " + Microloader.manifest.url);\r
550 //</debug>\r
551 Boot.fetch(Microloader.manifest.url, Microloader.onUpdatedManifestLoaded);\r
552 },\r
553\r
554 onAppCacheError: function(e) {\r
555 _warn(e.message);\r
556\r
557 Microloader.appCacheState = 'error';\r
558 Microloader.notifyUpdateReady();\r
559 },\r
560\r
561 onAppCacheReady: function() {\r
562 _cache.swapCache();\r
563 Microloader.appCacheUpdated();\r
564 },\r
565\r
566 onAppCacheObsolete: function() {\r
567 Microloader.appCacheUpdated();\r
568 },\r
569\r
570 appCacheUpdated: function() {\r
571 //<debug>\r
572 _debug("App Cache Updated");\r
573 //</debug>\r
574 Microloader.appCacheState = 'updated';\r
575 Microloader.notifyUpdateReady();\r
576 },\r
577\r
578 onAppCacheNotUpdated: function() {\r
579 //<debug>\r
580 _debug("App Cache Not Updated Callback");\r
581 //</debug>\r
582 Microloader.appCacheState = 'current';\r
583 Microloader.notifyUpdateReady();\r
584 },\r
585\r
586 onUpdatedManifestLoaded: function (result) {\r
587 result = Microloader.parseResult(result);\r
588 \r
589 if (!result.error) {\r
590 var currentAssets, newAssets, currentAsset, newAsset, prop,\r
591 assets, deltas, deltaPath, include,\r
592 updatingAssets = [],\r
593 manifest = new Manifest({\r
594 url: Microloader.manifest.url,\r
595 content: result.content,\r
596 assetCache: false\r
597 });\r
598\r
599 Microloader.remainingUpdatingAssets = 0;\r
600 Microloader.updatedAssets = [];\r
601 Microloader.removedAssets = [];\r
602 Microloader.updatedManifest = null;\r
603 Microloader.updatedAssetsReady = false;\r
604\r
605 // If the updated manifest has turned off caching we need to clear out all local storage\r
606 // and trigger a appupdate as all content is now uncached\r
607 if (!manifest.shouldCache()) {\r
608 //<debug>\r
609 _debug("New Manifest has caching disabled, clearing out any private storage");\r
610 //</debug>\r
611\r
612 Microloader.updatedManifest = manifest;\r
613 LocalStorage.clearAllPrivate();\r
614 Microloader.onAllUpdatedAssetsReady();\r
615 return;\r
616 }\r
617\r
618 // Manifest itself has changed\r
619 if (!Microloader.manifest.is(manifest)) {\r
620 Microloader.updatedManifest = manifest;\r
621\r
622 currentAssets = Microloader.manifest.getAssets();\r
623 newAssets = manifest.getAssets();\r
624\r
625 // Look through new assets for assets that do not exist or assets that have different versions\r
626 for (prop in newAssets) {\r
627 newAsset = newAssets[prop];\r
628 currentAsset = Microloader.manifest.getAsset(newAsset.assetConfig.path);\r
629 include = !(newAsset.assetConfig.platform && !Boot.filterPlatform(newAsset.assetConfig.platform));\r
630\r
631 if (include && (!currentAsset || (newAsset.shouldCache() && (!currentAsset.is(newAsset))))) {\r
632 //<debug>\r
633 _debug("New/Updated Version of Asset: " + newAsset.assetConfig.path + " was found in new manifest");\r
634 //</debug>\r
635 updatingAssets.push({_new: newAsset, _current: currentAsset});\r
636 }\r
637 }\r
638\r
639 // Look through current assets for stale/old assets that have been removed\r
640 for (prop in currentAssets) {\r
641 currentAsset = currentAssets[prop];\r
642 newAsset = manifest.getAsset(currentAsset.assetConfig.path);\r
643\r
644 //New version of this asset has been filtered out\r
645 include = !(newAsset.assetConfig.platform && !Boot.filterPlatform(newAsset.assetConfig.platform));\r
646\r
647 if (!include || !newAsset || (currentAsset.shouldCache() && !newAsset.shouldCache())) {\r
648 //<debug>\r
649 _debug("Asset: " + currentAsset.assetConfig.path + " was not found in new manifest, has been filtered out or has been switched to not cache. Marked for removal");\r
650 //</debug>\r
651 Microloader.removedAssets.push(currentAsset);\r
652 }\r
653 }\r
654\r
655 // Loop through all assets that need updating\r
656 if (updatingAssets.length > 0) {\r
657 Microloader.remainingUpdatingAssets = updatingAssets.length;\r
658 while (updatingAssets.length > 0) {\r
659 assets = updatingAssets.pop();\r
660 newAsset = assets._new;\r
661 currentAsset = assets._current;\r
662\r
663 // Full Updates will simply download the file and replace its current content\r
664 if (newAsset.assetConfig.update === "full" || !currentAsset) {\r
665\r
666 //<debug>\r
667 if (newAsset.assetConfig.update === "delta") {\r
668 _debug("Delta updated asset found without current asset available: " + newAsset.assetConfig.path + " fetching full file");\r
669 } else {\r
670 _debug("Full update found for: " + newAsset.assetConfig.path + " fetching");\r
671 }\r
672 //</debug>\r
673\r
674 // Load the asset and cache its its content into Boot to be evaluated in sequence\r
675 Boot.fetch(newAsset.assetConfig.path, (function (asset) {\r
676 return function (result) {\r
677 Microloader.onFullAssetUpdateLoaded(asset, result)\r
678 };\r
679 }(newAsset))\r
680 );\r
681\r
682 // Delta updates will be given a delta patch\r
683 } else if (newAsset.assetConfig.update === "delta") {\r
684 deltas = manifest.deltas;\r
685 deltaPath = deltas + "/" + newAsset.assetConfig.path + "/" + currentAsset.assetConfig.hash + ".json";\r
686 // Fetch the Delta Patch and update the contents of the asset\r
687 //<debug>\r
688 _debug("Delta update found for: " + newAsset.assetConfig.path + " fetching");\r
689 //</debug>\r
690 Boot.fetch(deltaPath,\r
691 (function (asset, oldAsset) {\r
692 return function (result) {\r
693 Microloader.onDeltaAssetUpdateLoaded(asset, oldAsset, result)\r
694 };\r
695 }(newAsset, currentAsset))\r
696 );\r
697 }\r
698 }\r
699 } else {\r
700 //<debug>\r
701 _debug("No Assets needed updating");\r
702 //</debug>\r
703 Microloader.onAllUpdatedAssetsReady();\r
704 }\r
705 } else {\r
706 //<debug>\r
707 _debug("Manifest files have matching hash's");\r
708 //</debug>\r
709 Microloader.onAllUpdatedAssetsReady();\r
710 }\r
711 } else {\r
712 _warn("Error loading manifest file to check for updates");\r
713 Microloader.onAllUpdatedAssetsReady();\r
714 }\r
715 },\r
716\r
717 onFullAssetUpdateLoaded: function(asset, result) {\r
718 var checksum;\r
719 result = Microloader.parseResult(result);\r
720 Microloader.remainingUpdatingAssets--;\r
721 \r
722 if (!result.error) {\r
723 \r
724 checksum = Microloader.checksum(asset.assetConfig.hash, result.content);\r
725 //<debug>\r
726 _debug("Checksum for Full asset: " + asset.assetConfig.path + " is " + checksum);\r
727 //</debug>\r
728 if (!checksum) {\r
729 //<debug>\r
730 _debug("Full Update Asset: " + asset.assetConfig.path + " has failed checksum. This asset will be uncached for future loading");\r
731 //</debug>\r
732\r
733 // uncache this asset as there is a new version somewhere that has not been loaded.\r
734 asset.uncache();\r
735 } else {\r
736 asset.updateContent(result.content);\r
737 Microloader.updatedAssets.push(asset);\r
738 }\r
739 } else {\r
740 //<debug>\r
741 _debug("Error loading file at" + asset.assetConfig.path + ". This asset will be uncached for future loading");\r
742 //</debug>\r
743 \r
744 // uncache this asset as there is a new version somewhere that has not been loaded.\r
745 asset.uncache();\r
746 }\r
747\r
748 if (Microloader.remainingUpdatingAssets === 0) {\r
749 Microloader.onAllUpdatedAssetsReady();\r
750 }\r
751 },\r
752\r
753 onDeltaAssetUpdateLoaded: function(asset, oldAsset, result) {\r
754 var json, checksum, content;\r
755 result = Microloader.parseResult(result);\r
756 Microloader.remainingUpdatingAssets--;\r
757\r
758 if (!result.error) {\r
759 //<debug>\r
760 _debug("Delta patch loaded successfully, patching content");\r
761 //</debug>\r
762 try {\r
763 json = JSON.parse(result.content);\r
764 content = Microloader.patch(oldAsset.content, json);\r
765 checksum = Microloader.checksum(content, asset.assetConfig.hash);\r
766 //<debug>\r
767 _debug("Checksum for Delta Patched asset: " + asset.assetConfig.path + " is " + checksum);\r
768 //</debug>\r
769 if (!checksum) {\r
770 //<debug>\r
771 _debug("Delta Update Asset: " + asset.assetConfig.path + " has failed checksum. This asset will be uncached for future loading");\r
772 //</debug>\r
773\r
774 // uncache this asset as there is a new version somewhere that has not been loaded.\r
775 asset.uncache();\r
776 } else {\r
777 asset.updateContent(content);\r
778 Microloader.updatedAssets.push(asset);\r
779 }\r
780 } catch (e) {\r
781 _warn("Error parsing delta patch for " + asset.assetConfig.path + " with hash " + oldAsset.assetConfig.hash + " . This asset will be uncached for future loading");\r
782 // uncache this asset as there is a new version somewhere that has not been loaded.\r
783 asset.uncache();\r
784 }\r
785 } else {\r
786 _warn("Error loading delta patch for " + asset.assetConfig.path + " with hash " + oldAsset.assetConfig.hash + " . This asset will be uncached for future loading");\r
787\r
788 // uncache this asset as there is a new version somewhere that has not been loaded.\r
789 asset.uncache();\r
790 }\r
791 if (Microloader.remainingUpdatingAssets === 0) {\r
792 Microloader.onAllUpdatedAssetsReady();\r
793 }\r
794 },\r
795\r
796 //TODO: Make this all transaction based to allow for reverting if quota is exceeded\r
797 onAllUpdatedAssetsReady: function() {\r
798 var asset;\r
799 Microloader.updatedAssetsReady = true;\r
800\r
801 if (Microloader.updatedManifest) {\r
802 while (Microloader.removedAssets.length > 0) {\r
803 asset = Microloader.removedAssets.pop();\r
804 //<debug>\r
805 _debug("Asset: " + asset.assetConfig.path + " was removed, un-caching");\r
806 //</debug>\r
807 asset.uncache();\r
808 }\r
809\r
810 if (Microloader.updatedManifest) {\r
811 //<debug>\r
812 _debug("Manifest was updated, re-caching");\r
813 //</debug>\r
814 Microloader.updatedManifest.cache();\r
815 }\r
816\r
817 while (Microloader.updatedAssets.length > 0) {\r
818 asset = Microloader.updatedAssets.pop();\r
819 //<debug>\r
820 _debug("Asset: " + asset.assetConfig.path + " was updated, re-caching");\r
821 //</debug>\r
822 asset.cache();\r
823 }\r
824\r
825 }\r
826\r
827 Microloader.notifyUpdateReady();\r
828 },\r
829\r
830 notifyUpdateReady: function () {\r
831 if (Microloader.appCacheState !== 'checking' && Microloader.updatedAssetsReady) {\r
832 if (Microloader.appCacheState === 'updated' || Microloader.updatedManifest) {\r
833 //<debug>\r
834 _debug("There was an update here you will want to reload the app, trigger an event");\r
835 //</debug>\r
836 Microloader.appUpdate = {\r
837 updated: true,\r
838 app: Microloader.appCacheState === 'updated',\r
839 manifest: Microloader.updatedManifest && Microloader.updatedManifest.exportContent()\r
840 };\r
841\r
842 Microloader.fireAppUpdate();\r
843 }\r
844 //<debug>\r
845 else {\r
846 _debug("AppCache and LocalStorage Cache are current, no updating needed");\r
847 Microloader.appUpdate = {};\r
848 }\r
849 //</debug>\r
850 }\r
851 },\r
852 \r
853 fireAppUpdate: function() {\r
854 if (Ext.GlobalEvents) {\r
855 // We defer dispatching this event slightly in order to let the application finish loading\r
856 // as we are still very early in the lifecycle\r
857 Ext.defer(function() {\r
858 Ext.GlobalEvents.fireEvent('appupdate', Microloader.appUpdate);\r
859 }, 100);\r
860 }\r
861 },\r
862 \r
863 checksum: function(content, hash) {\r
864 var passed = true,\r
865 hashLn = hash.length,\r
866 checksumType = content.substring(0, 1);\r
867 \r
868 if (checksumType == '/') {\r
869 if (content.substring(2, hashLn + 2) !== hash) {\r
870 passed = false;\r
871 }\r
872 } else if (checksumType == 'f') {\r
873 if (content.substring(10, hashLn + 10) !== hash) {\r
874 passed = false;\r
875 }\r
876 } else if (checksumType == '.') {\r
877 if (content.substring(1, hashLn + 1) !== hash) {\r
878 passed = false;\r
879 }\r
880 }\r
881 return passed;\r
882 },\r
883 parseResult: function(result) {\r
884 var rst = {};\r
885 if ((result.exception || result.status === 0) && !Boot.env.phantom) {\r
886 rst.error = true;\r
887 } else if ((result.status >= 200 && result.status < 300) || result.status === 304\r
888 || Boot.env.phantom\r
889 || (result.status === 0 && result.content.length > 0)\r
890 ) {\r
891 rst.content = result.content;\r
892 } else {\r
893 rst.error = true;\r
894 }\r
895 return rst;\r
896 }\r
897 };\r
898\r
899 return Microloader;\r
900}());\r
901\r
902//</editor-fold>\r
903\r
904/**\r
905 * the current application manifest\r
906 *\r
907 *\r
908 * {\r
909 * name: 'name',\r
910 * version: <checksum>,\r
911 * debug: {\r
912 * hooks: {\r
913 * "*": true\r
914 * }\r
915 * },\r
916 * localStorage: false,\r
917 * mode: production,\r
918 * js: [\r
919 * ...\r
920 * {\r
921 * path: '../boo/baz.js',\r
922 * version: <checksum>,\r
923 * update: full | delta | <falsy>,\r
924 * platform: ['phone', 'ios', 'android']\r
925 * },\r
926 * {\r
927 * path: 'http://some.domain.com/api.js',\r
928 * remote: true\r
929 * },\r
930 * ...\r
931 * ],\r
932 * css: [\r
933 * ...\r
934 * {\r
935 * path: '../boo/baz.css',\r
936 * version: <checksum>,\r
937 * update: full | delta | <falsy>,\r
938 * platform: ['phone', 'ios', 'android']\r
939 * },\r
940 * ...\r
941 * ],\r
942 * localStorage: false,\r
943 * paths: {...},\r
944 * loadOrder: [\r
945 * ...\r
946 * {\r
947 * path: '../foo/bar.js",\r
948 * idx: 158,\r
949 * requires; [1,2,3,...,145,157],\r
950 * uses: [182, 193]\r
951 * },\r
952 * ...\r
953 * ],\r
954 * classes: {\r
955 * ...\r
956 * 'Ext.panel.Panel': {\r
957 * requires: [...],\r
958 * uses: [...],\r
959 * aliases: [...],\r
960 * alternates: [...],\r
961 * mixins: [...]\r
962 * },\r
963 * 'Ext.rtl.util.Renderable': {\r
964 * requires: [...],\r
965 * uses: [...],\r
966 * aliases: [...],\r
967 * alternates: [...],\r
968 * mixins: [...]\r
969 * override: 'Ext.util.Renderable'\r
970 * },\r
971 * ...\r
972 * },\r
973 * packages: {\r
974 * ...\r
975 * "sencha-core": {\r
976 * version: '1.2.3.4',\r
977 * requires: []\r
978 * },\r
979 * "ext": {\r
980 * version: '5.0.0.0',\r
981 * requires: ["sencha-core"]\r
982 * }.\r
983 * ...\r
984 * }\r
985 * }\r
986 *\r
987 *\r
988 * @type {String/Object}\r
989 */\r
990Ext.manifest = Ext.manifest || "bootstrap";\r
991\r
992Ext.Microloader.run();