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