]> git.proxmox.com Git - sencha-touch.git/blob - src/examples/nestedlist/.sencha/app/microloader/production.js
import Sencha Touch 2.4.2 source
[sencha-touch.git] / src / examples / nestedlist / .sencha / app / microloader / production.js
1 /**
2 * Sencha Blink
3 * @author Jacky Nguyen <jacky@sencha.com>
4 */
5 (function(global) {
6 var emptyFn = function(){},
7 callbacks = [],
8 doc = global.document,
9 head = doc.head || doc.getElementsByTagName('head')[0],
10 addWindowListener = global.addEventListener,
11 removeWindowListener = global.removeEventListener,
12 jsonParse = JSON.parse,
13 a = doc.createElement('a'),
14 documentLocation = doc.location,
15 documentUri = documentLocation.protocol + '//' + documentLocation.hostname + documentLocation.pathname + documentLocation.search,
16 manifestFile = 'app.json',
17 isRefreshing = false,
18 activeManifest, appCache, storage;
19
20 try {
21 storage = global.localStorage;
22 appCache = global.applicationCache;
23 }
24 catch(e) {}
25
26 function getManifestStorageKey(id) {
27 return id + '-' + documentUri + manifestFile;
28 }
29
30 function Manifest(manifest) {
31 var manifestContent;
32
33 if (typeof manifest == 'string') {
34 manifestContent = manifest;
35 manifest = jsonParse(manifestContent);
36 }
37 else {
38 manifestContent = JSON.stringify(manifest);
39 }
40
41 var applicationId = manifest.id,
42 key = getManifestStorageKey(applicationId),
43 assetMap = {};
44
45 function processAsset(asset) {
46 var uri;
47
48 if (typeof asset == 'string') {
49 asset = {
50 path: asset
51 };
52 }
53
54 if (asset.shared) {
55 asset.version = asset.shared;
56 uri = asset.shared + asset.path;
57 }
58 else {
59 uri = toAbsoluteUri(asset.path);
60 }
61
62 asset.uri = uri;
63 asset.key = applicationId + '-' + uri;
64 assetMap[uri] = asset;
65
66 return asset;
67 }
68
69 function processAssets(assets, type) {
70 var ln = assets.length,
71 i, asset;
72
73 for (i = 0; i < ln; i++) {
74 asset = assets[i];
75
76 assets[i] = asset = processAsset(asset);
77
78 asset.type = type;
79 asset.index = i;
80 asset.collection = assets;
81 asset.ready = false;
82 asset.evaluated = false;
83 }
84
85 return assets;
86 }
87
88 this.key = key;
89 this.css = processAssets(manifest.css, 'css');
90 this.js = processAssets(manifest.js, 'js');
91
92 Ext.microloaded = true;
93
94 var filterPlatform = window.Ext.filterPlatform = function(platform) {
95 var profileMatch = false,
96 ua = navigator.userAgent,
97 j, jln;
98
99 platform = [].concat(platform);
100
101 function isPhone(ua) {
102 var isMobile = /Mobile(\/|\s)/.test(ua);
103
104 // Either:
105 // - iOS but not iPad
106 // - Android 2
107 // - Android with "Mobile" in the UA
108
109 return /(iPhone|iPod)/.test(ua) ||
110 (!/(Silk)/.test(ua) && (/(Android)/.test(ua) && (/(Android 2)/.test(ua) || isMobile))) ||
111 (/(BlackBerry|BB)/.test(ua) && isMobile) ||
112 /(Windows Phone)/.test(ua);
113 }
114
115 function isTablet(ua) {
116 return !isPhone(ua) && (/iPad/.test(ua) || /Android|Silk/.test(ua) || /(RIM Tablet OS)/.test(ua) ||
117 (/MSIE 10/.test(ua) && /; Touch/.test(ua)));
118 }
119
120 // Check if the ?platform parameter is set in the URL
121 var paramsString = window.location.search.substr(1),
122 paramsArray = paramsString.split("&"),
123 params = {},
124 testPlatform, i;
125
126 for (i = 0; i < paramsArray.length; i++) {
127 var tmpArray = paramsArray[i].split("=");
128 params[tmpArray[0]] = tmpArray[1];
129 }
130
131 testPlatform = params.platform;
132 if (testPlatform) {
133 return platform.indexOf(testPlatform) != -1;
134 }
135
136 for (j = 0, jln = platform.length; j < jln; j++) {
137 switch (platform[j]) {
138 case 'phone':
139 profileMatch = isPhone(ua);
140 break;
141 case 'tablet':
142 profileMatch = isTablet(ua);
143 break;
144 case 'desktop':
145 profileMatch = !isPhone(ua) && !isTablet(ua);
146 break;
147 case 'ios':
148 profileMatch = /(iPad|iPhone|iPod)/.test(ua);
149 break;
150 case 'android':
151 profileMatch = /(Android|Silk)/.test(ua);
152 break;
153 case 'blackberry':
154 profileMatch = /(BlackBerry|BB)/.test(ua);
155 break;
156 case 'safari':
157 profileMatch = /Safari/.test(ua) && !(/(BlackBerry|BB)/.test(ua));
158 break;
159 case 'chrome':
160 profileMatch = /Chrome/.test(ua);
161 break;
162 case 'ie10':
163 profileMatch = /MSIE 10/.test(ua);
164 break;
165 case 'windows':
166 profileMatch = /MSIE 10/.test(ua) || /Trident/.test(ua);
167 break;
168 case 'tizen':
169 profileMatch = /Tizen/.test(ua);
170 break;
171 case 'firefox':
172 profileMatch = /Firefox/.test(ua);
173 }
174 if (profileMatch) {
175 return true;
176 }
177 }
178 return false;
179 };
180
181 this.css = this.css.filter(function(css) {
182 var platform = css.platform,
183 exclude = css.exclude;
184
185 css.type = "css";
186
187 if (platform) {
188 if (filterPlatform(platform) && !filterPlatform(exclude)) {
189 if(!Ext.theme) {
190 Ext.theme = {};
191 }
192 if(!Ext.theme.name) {
193 Ext.theme.name = css.theme || 'Default';
194 }
195 return true;
196 }
197 css.filtered = true;
198 return false;
199 }
200 return true;
201 });
202
203 this.js = this.js.filter(function(js) {
204 var platform = js.platform,
205 exclude = js.exclude;
206
207 js.type = "js";
208
209 if (platform) {
210 if (filterPlatform(platform) && !filterPlatform(exclude)) {
211 return true;
212 }
213 else {
214 js.filtered = true;
215 return false;
216 }
217 }
218 return true;
219 });
220
221 this.assets = this.css.concat(this.js);
222 this.getAsset = function(uri) {
223 return assetMap[uri];
224 };
225 this.store = function() {
226 store(key, manifestContent);
227 };
228 }
229
230 if (typeof global.Ext === 'undefined') {
231 var Ext = global.Ext = {};
232 }
233
234 function toAbsoluteUri(uri) {
235 a.href = uri;
236 return a.href;
237 }
238
239 function addMeta(name, content) {
240 var meta = document.createElement('meta');
241
242 meta.setAttribute('name', name);
243 meta.setAttribute('content', content);
244 head.appendChild(meta);
245 }
246
247 function request(uri, isShared, onSuccess, onFailure) {
248 (isShared ? requestIframe : requestXhr)(uri, onSuccess, onFailure);
249 }
250
251 function requestXhr(uri, onSuccess, onFailure) {
252 var xhr = new XMLHttpRequest();
253
254 onFailure = onFailure || emptyFn;
255
256 uri = uri + ((uri.indexOf('?') == -1) ? '?' : '&') + Date.now();
257
258 try {
259 xhr.open('GET', uri, true);
260 xhr.onreadystatechange = function() {
261 if (xhr.readyState == 4) {
262 var status = xhr.status,
263 content = xhr.responseText;
264
265 if ((status >= 200 && status < 300) || status == 304 || (status == 0 && content.length > 0)) {
266 onSuccess(content);
267 }
268 else {
269 onFailure();
270 }
271 }
272 };
273 xhr.send(null);
274 } catch (e) {
275 onFailure();
276 }
277 }
278
279 function requestIframe(uri, onSuccess) {
280 var iframe = doc.createElement('iframe');
281
282 callbacks.push({
283 iframe: iframe,
284 callback: onSuccess
285 });
286
287 iframe.src = uri + '.html';
288 iframe.style.cssText = 'width:0;height:0;border:0;position:absolute;z-index:-999;visibility:hidden';
289 doc.body.appendChild(iframe);
290 }
291
292 // for remote assets, inject a script element
293 function addRemoteScript(uri, onSuccess, onFailure) {
294 var script = document.createElement('script');
295 script.src = uri;
296 script.type = "text/javascript";
297 script.charset = "UTF-8";
298
299 script.onerror = onFailure;
300
301 if ('addEventListener' in script ) {
302 script.onload = onSuccess;
303 } else if ('readyState' in script) {
304 script.onreadystatechange = function() {
305 if (this.readyState === 'loaded' ||
306 this.readyState === 'complete') {
307 onSuccess();
308 }
309 };
310 } else {
311 script.onload = onSuccess;
312 }
313
314 head.appendChild(script);
315 }
316
317 function addRemoteLink(uri) {
318 var link = document.createElement('link');
319 link.rel = "stylesheet";
320 link.href = uri;
321 head.appendChild(link);
322 }
323
324 function requestAsset(asset, onSuccess, onFailure) {
325 var isRemote = !!asset.remote,
326 isShared = !!asset.shared;
327
328 if (isRemote) {
329 if(asset.type === "js") {
330 addRemoteScript(asset.uri, function(){
331 onSuccess('');
332 }, onFailure);
333 } else {
334 addRemoteLink(asset.uri);
335 onSuccess('');
336 }
337 return;
338 }
339
340 if (!isShared && asset.version && asset.version.length) {
341 var onRequestSuccess = onSuccess,
342 version = asset.version,
343 versionLn = version.length,
344 checksumFail, checksumType;
345
346 onSuccess = function(content) {
347 checksumType = content.substring(0, 1);
348 if (checksumType == '/') {
349 if (content.substring(2, versionLn + 2) !== version) {
350 checksumFail = true;
351 }
352 }
353 else if (checksumType == 'f') {
354 if (content.substring(10, versionLn + 10) !== version) {
355 checksumFail = true;
356 }
357 }
358 else if (checksumType == '.') {
359 if (content.substring(1, versionLn + 1) !== version) {
360 checksumFail = true;
361 }
362 }
363 if (checksumFail === true) {
364 if (confirm("Requested: '" + asset.uri + " seems to have been changed. Attempt to refresh the application?")) {
365 refresh();
366 }
367 return;
368 }
369 onRequestSuccess(content);
370 };
371 }
372
373 request(asset.uri, isShared, onSuccess, onFailure);
374 }
375
376 function onMessage(e) {
377 var data = e.data,
378 sourceWindow = e.source.window,
379 i, ln, callback, iframe;
380
381 for (i = 0, ln = callbacks.length; i < ln; i++) {
382 callback = callbacks[i];
383 iframe = callback.iframe;
384
385 if (iframe.contentWindow === sourceWindow) {
386 callback.callback(data);
387 doc.body.removeChild(iframe);
388 callbacks.splice(i, 1);
389 return;
390 }
391 }
392 }
393
394 function patch(content, delta) {
395 var output = [],
396 chunk, i, ln;
397
398 if (delta.length === 0) {
399 return content;
400 }
401
402 for (i = 0,ln = delta.length; i < ln; i++) {
403 chunk = delta[i];
404
405 if (typeof chunk === 'number') {
406 output.push(content.substring(chunk, chunk + delta[++i]));
407 }
408 else {
409 output.push(chunk);
410 }
411 }
412
413 return output.join('');
414 }
415
416 function log(message) {
417 if (typeof console != 'undefined') {
418 (console.error || console.log).call(console, message);
419 }
420 }
421
422 function store(key, value) {
423 try {
424 storage.setItem(key, value);
425 }
426 catch (e) {
427 if (storage && e.code == e.QUOTA_EXCEEDED_ERR && activeManifest) {
428 log("LocalStorage Quota exceeded, cannot store " + key + " locally");
429 // Quota exceeded, clean up unused items
430 // var items = activeManifest.assets.map(function(asset) {
431 // return asset.key;
432 // }),
433 // i = 0,
434 // ln = storage.length,
435 // cleaned = false,
436 // item;
437 //
438 // items.push(activeManifest.key);
439 //
440 // while (i <= ln - 1) {
441 // item = storage.key(i);
442 //
443 // if (items.indexOf(item) == -1) {
444 // storage.removeItem(item);
445 // cleaned = true;
446 // ln--;
447 // }
448 // else {
449 // i++;
450 // }
451 // }
452
453 // Done cleaning up, attempt to store the value again
454 // If there's still not enough space, no other choice
455 // but to skip this item from being stored
456 // if (cleaned) {
457 // store(key, value);
458 // }
459 }
460 }
461 }
462
463 function retrieve(key) {
464 try {
465 return storage.getItem(key);
466 }
467 catch (e) {
468 // Private browsing mode
469 return null;
470 }
471 }
472
473 function retrieveAsset(asset) {
474 return retrieve(asset.key);
475 }
476
477 function storeAsset(asset, content) {
478 return store(asset.key, content);
479 }
480
481 function refresh() {
482 if (!isRefreshing) {
483 isRefreshing = true;
484 requestXhr(manifestFile, function(content) {
485 new Manifest(content).store();
486 global.location.reload();
487 });
488 }
489 }
490
491 function blink(currentManifest) {
492 var currentAssets = currentManifest.assets,
493 assetsCount = currentAssets.length,
494 newManifest;
495
496 activeManifest = currentManifest;
497
498 addWindowListener('message', onMessage, false);
499
500 function onAssetReady(asset, content) {
501 var assets = asset.collection,
502 index = asset.index,
503 ln = assets.length,
504 i;
505
506 asset.ready = true;
507 asset.content = content;
508
509 for (i = index - 1; i >= 0; i--) {
510 asset = assets[i];
511 if (!asset.filtered && (!asset.ready || !asset.evaluated)) {
512 return;
513 }
514 }
515
516 for (i = index; i < ln; i++) {
517 asset = assets[i];
518 if (asset.ready) {
519 if (!asset.evaluated) {
520 evaluateAsset(asset);
521 }
522 }
523 else {
524 return;
525 }
526 }
527 }
528
529 function evaluateAsset(asset) {
530 asset.evaluated = true;
531
532 if (asset.type == 'js') {
533 try {
534 eval(asset.content);
535 }
536 catch (e) {
537 log("Error evaluating " + asset.uri + " with message: " + e);
538 }
539 }
540 else {
541 var style = doc.createElement('style'),
542 base;
543
544 style.type = 'text/css';
545 style.textContent = asset.content;
546
547 if ('id' in asset) {
548 style.id = asset.id;
549 }
550
551 if ('disabled' in asset) {
552 style.disabled = asset.disabled;
553 }
554
555 base = document.createElement('base');
556 base.href = asset.path.replace(/\/[^\/]*$/, '/');
557 head.appendChild(base);
558 head.appendChild(style);
559 head.removeChild(base);
560 }
561
562 delete asset.content;
563
564 if (--assetsCount == 0) {
565 onReady();
566 }
567 }
568
569 function onReady() {
570 var updatingAssets = [],
571 appCacheReady = false,
572 onAppCacheIdle = function() {},
573 onAppCacheReady = function() {
574 appCache.swapCache();
575 appCacheReady = true;
576 onAppCacheIdle();
577 },
578 updatingCount;
579
580 removeWindowListener('message', onMessage, false);
581
582 if (appCache.status == appCache.UPDATEREADY) {
583 onAppCacheReady();
584 }
585 else if (appCache.status == appCache.CHECKING || appCache.status == appCache.DOWNLOADING) {
586 appCache.onupdateready = onAppCacheReady;
587 appCache.onnoupdate = appCache.onobsolete = function() {
588 onAppCacheIdle();
589 };
590 }
591
592 function notifyUpdateIfAppCacheReady() {
593 if (appCacheReady) {
594 notifyUpdate();
595 }
596 }
597
598 function notifyUpdate() {
599 var updatedCallback = Ext.onUpdated || emptyFn;
600
601 if ('onSetup' in Ext) {
602 Ext.onSetup(updatedCallback);
603 }
604 else {
605 updatedCallback();
606 }
607 }
608
609 function doUpdate() {
610 newManifest.store();
611
612 updatingAssets.forEach(function(asset) {
613 storeAsset(asset, asset.content);
614 });
615
616 notifyUpdate();
617 }
618
619 function onAssetUpdated(asset, content) {
620 asset.content = content;
621
622 if (--updatingCount == 0) {
623 if (appCache.status == appCache.IDLE) {
624 doUpdate();
625 }
626 else {
627 onAppCacheIdle = doUpdate;
628 }
629 }
630 }
631
632 function checkForUpdate() {
633 removeWindowListener('online', checkForUpdate, false);
634 requestXhr(manifestFile, function(manifestContent) {
635 activeManifest = newManifest = new Manifest(manifestContent);
636
637 var assets = newManifest.assets,
638 currentAsset;
639
640 assets.forEach(function(asset) {
641 currentAsset = currentManifest.getAsset(asset.uri);
642
643 if (!currentAsset || asset.version !== currentAsset.version) {
644 updatingAssets.push(asset);
645 }
646 });
647
648 updatingCount = updatingAssets.length;
649
650 if (updatingCount == 0) {
651 if (appCache.status == appCache.IDLE) {
652 notifyUpdateIfAppCacheReady();
653 }
654 else {
655 onAppCacheIdle = notifyUpdateIfAppCacheReady;
656 }
657 return;
658 }
659
660 updatingAssets.forEach(function(asset) {
661 var currentAsset = currentManifest.getAsset(asset.uri),
662 path = asset.path,
663 update = asset.update;
664
665 function updateFull() {
666 requestAsset(asset, function(content) {
667 onAssetUpdated(asset, content);
668 });
669 }
670
671 // New asset (never used before)
672 // OR Shared from CDN
673 // OR Missing local storage
674 // OR Full update
675 if (!currentAsset || !update || retrieveAsset(asset) === null || update != 'delta') {
676 updateFull();
677 }
678 else {
679 requestXhr('deltas/' + path + '/' + currentAsset.version + '.json',
680 function(content) {
681 try {
682 onAssetUpdated(asset, patch(retrieveAsset(asset), jsonParse(content)));
683 }
684 catch (e) {
685 log("Malformed delta content received for " + asset.uri);
686 }
687 },
688 updateFull
689 );
690 }
691 })
692 });
693 }
694
695 if (navigator.onLine !== false) {
696 checkForUpdate();
697 }
698 else {
699 addWindowListener('online', checkForUpdate, false);
700 }
701 }
702
703 if (assetsCount == 0) {
704 onReady();
705 return;
706 }
707
708 currentAssets.forEach(function(asset) {
709 var content = retrieveAsset(asset);
710
711 if (content === null) {
712 requestAsset(asset, function(content) {
713 if (!asset.remote) {
714 storeAsset(asset, content);
715 }
716 onAssetReady(asset, content);
717 }, function() {
718 onAssetReady(asset, '');
719 });
720 }
721 else {
722 onAssetReady(asset, content);
723 }
724 });
725 }
726
727 function blinkOnDomReady(manifest) {
728 if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
729 var msViewportStyle = document.createElement("style");
730 msViewportStyle.appendChild(
731 document.createTextNode(
732 "@media screen and (orientation: portrait) {" +
733 "@-ms-viewport {width: 320px !important;}" +
734 "}" +
735 "@media screen and (orientation: landscape) {" +
736 "@-ms-viewport {width: 560px !important;}" +
737 "}"
738 )
739 );
740 document.getElementsByTagName("head")[0].appendChild(msViewportStyle);
741 }
742
743 var readyStateRe = (/MSIE 10/.test(navigator.userAgent)) ? /complete|loaded/ : /interactive|complete|loaded/;
744 if (doc.readyState.match(readyStateRe) !== null) {
745 blink(manifest);
746 }
747 else {
748 addWindowListener('DOMContentLoaded', function() {
749 if (navigator.standalone) {
750 // When running from Home Screen, the splash screen will not disappear until all
751 // external resource requests finish.
752 // The first timeout clears the splash screen
753 // The second timeout allows inital HTML content to be displayed
754 setTimeout(function() {
755 setTimeout(function() {
756 blink(manifest);
757 }, 1);
758 }, 1);
759 }
760 else {
761 setTimeout(function() {
762 blink(manifest);
763 }, 1);
764 }
765 }, false);
766 }
767 }
768
769 Ext.blink = function(manifest) {
770 var manifestContent = retrieve(getManifestStorageKey(manifest.id));
771
772 addMeta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no');
773 addMeta('apple-mobile-web-app-capable', 'yes');
774 addMeta('apple-touch-fullscreen', 'yes');
775
776 if (manifestContent) {
777 manifest = new Manifest(manifestContent);
778 blinkOnDomReady(manifest);
779 }
780 else {
781 requestXhr(manifestFile, function(content) {
782 manifest = new Manifest(content);
783 manifest.store();
784 blinkOnDomReady(manifest);
785 });
786 }
787 };
788 })(this);