Форк Rambox
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

959 lines
39 KiB

// here, the extra check for window['Ext'] is needed for use with cmd-test
// code injection. we need to make that this file will sync up with page global
// scope to avoid duplicate Ext.Boot state. That check is after the initial Ext check
// to allow the sandboxing template to inject an appropriate Ext var and prevent the
// global detection.
var Ext = Ext || window['Ext'] || {};
//<editor-fold desc="Microloader">
/**
* @class Ext.Microloader
* @private
* @singleton
*/
Ext.Microloader = Ext.Microloader || (function () {
var Boot = Ext.Boot,
//<debug>
_debug = function (message) {
//console.log(message);
},
//</debug>
_warn = function (message) {
console.log("[WARN] " + message);
},
_privatePrefix = '_ext:' + location.pathname,
/**
* @method getStorageKey
* The Following combination is used to create isolated local storage keys
* '_ext' is used to scope all the local storage keys that we internally by Ext
* 'location.pathname' is used to force each assets to cache by an absolute URL (/build/MyApp) (dev vs prod)
* 'url' is used to force each asset to cache relative to the page (app.json vs resources/app.css)
* 'profileId' is used to differentiate the builds of an application (neptune vs crisp)
* 'Microloader.appId' is unique to the application and will differentiate apps on the same host (dev mode running app watch against multiple apps)
*/
getStorageKey = function(url, profileId) {
return _privatePrefix + url + '-' + (profileId ? profileId + '-' : '') + Microloader.appId;
},
postProcessor, _storage;
try {
_storage = window['localStorage'];
} catch(ex) {
// ignore
}
var _cache = window['applicationCache'],
// Local Storage Controller
LocalStorage = {
clearAllPrivate: function(manifest) {
if(_storage) {
//Remove the entry for the manifest first
_storage.removeItem(manifest.key);
var i, key,
removeKeys = [],
suffix = manifest.profile + '-' + Microloader.appId,
ln = _storage.length;
for (i = 0; i < ln; i++) {
key = _storage.key(i);
// If key starts with the private key and the suffix is present we can clear this entry
if (key.indexOf(_privatePrefix) === 0 && key.indexOf(suffix) !== -1) {
removeKeys.push(key);
}
}
for(i in removeKeys) {
//<debug>
_debug("Removing "+ removeKeys[i] + " from Local Storage");
//</debug>
_storage.removeItem(removeKeys[i]);
}
}
},
/**
* @private
*/
retrieveAsset: function (key) {
try {
return _storage.getItem(key);
}
catch (e) {
// Private browsing mode
return null;
}
},
setAsset: function(key, content) {
try {
if (content === null || content == '') {
_storage.removeItem(key);
} else {
_storage.setItem(key, content);
}
}
catch (e) {
if (_storage && e.code == e.QUOTA_EXCEEDED_ERR) {
//<debug>
_warn("LocalStorage Quota exceeded, cannot store " + key + " locally");
//</debug>
}
}
}
};
var Asset = function (cfg) {
if (typeof cfg.assetConfig === 'string') {
this.assetConfig = {
path: cfg.assetConfig
};
} else {
this.assetConfig = cfg.assetConfig;
}
this.type = cfg.type;
this.key = getStorageKey(this.assetConfig.path, cfg.manifest.profile);
if (cfg.loadFromCache) {
this.loadFromCache();
}
};
Asset.prototype = {
shouldCache: function() {
return _storage && this.assetConfig.update && this.assetConfig.hash && !this.assetConfig.remote;
},
is: function (asset) {
return (!!asset && this.assetConfig && asset.assetConfig && (this.assetConfig.hash === asset.assetConfig.hash))
},
cache: function(content) {
if (this.shouldCache()) {
LocalStorage.setAsset(this.key, content || this.content);
}
},
uncache: function() {
LocalStorage.setAsset(this.key, null);
},
updateContent: function (content) {
this.content = content;
},
getSize: function () {
return this.content ? this.content.length : 0;
},
loadFromCache: function() {
if (this.shouldCache()) {
this.content = LocalStorage.retrieveAsset(this.key);
}
}
};
var Manifest = function (cfg) {
if (typeof cfg.content === "string") {
this.content = JSON.parse(cfg.content);
} else {
this.content = cfg.content;
}
this.assetMap = {};
this.url = cfg.url;
this.fromCache = !!cfg.cached;
this.assetCache = !(cfg.assetCache === false);
this.key = getStorageKey(this.url);
// Pull out select properties for repetitive use
this.profile = this.content.profile;
this.hash = this.content.hash;
this.loadOrder = this.content.loadOrder;
this.deltas = this.content.cache ? this.content.cache.deltas : null;
this.cacheEnabled = this.content.cache ? this.content.cache.enable : false;
this.loadOrderMap = (this.loadOrder) ? Boot.createLoadOrderMap(this.loadOrder) : null;
var tags = this.content.tags,
platformTags = Ext.platformTags;
if (tags) {
if (tags instanceof Array) {
for (var i = 0; i < tags.length; i++) {
platformTags[tags[i]] = true;
}
} else {
Boot.apply(platformTags, tags);
}
// re-apply the query parameters, so that the params as specified
// in the url always has highest priority
Boot.apply(platformTags, Boot.loadPlatformsParam());
}
// Convert all assets into Assets
this.js = this.processAssets(this.content.js, 'js');
this.css = this.processAssets(this.content.css, 'css');
};
Manifest.prototype = {
processAsset: function(assetConfig, type) {
var processedAsset = new Asset({
manifest: this,
assetConfig: assetConfig,
type: type,
loadFromCache: this.assetCache
});
this.assetMap[assetConfig.path] = processedAsset;
return processedAsset;
},
processAssets: function(assets, type) {
var results = [],
ln = assets.length,
i, assetConfig;
for (i = 0; i < ln; i++) {
assetConfig = assets[i];
results.push(this.processAsset(assetConfig, type));
}
return results;
},
useAppCache: function() {
return true;
},
// Concatenate all assets for easy access
getAssets: function () {
return this.css.concat(this.js);
},
getAsset: function (path) {
return this.assetMap[path];
},
shouldCache: function() {
return this.hash && this.cacheEnabled;
},
cache: function(content) {
if (this.shouldCache()) {
LocalStorage.setAsset(this.key, JSON.stringify(content || this.content));
}
//<debug>
else {
_debug("Manifest caching is disabled.");
}
//</debug>
},
is: function(manifest) {
//<debug>
_debug("Testing Manifest: " + this.hash + " VS " + manifest.hash);
//</debug>
return this.hash === manifest.hash;
},
// Clear the manifest from local storage
uncache: function() {
LocalStorage.setAsset(this.key, null);
},
exportContent: function() {
return Boot.apply({
loadOrderMap: this.loadOrderMap
}, this.content);
}
};
/**
* Microloader
* @type {Array}
* @private
*/
var _listeners = [],
_loaded = false,
Microloader = {
init: function () {
Ext.microloaded = true;
// data-app is in the dev template for an application and is also
// injected into the app my CMD for production
// We use this to prefix localStorage cache to prevent collisions
var microloaderElement = document.getElementById('microloader');
Microloader.appId = microloaderElement ? microloaderElement.getAttribute('data-app') : '';
if (Ext.beforeLoad) {
postProcessor = Ext.beforeLoad(Ext.platformTags);
}
var readyHandler = Ext._beforereadyhandler;
Ext._beforereadyhandler = function () {
if (Ext.Boot !== Boot) {
Ext.apply(Ext.Boot, Boot);
Ext.Boot = Boot;
}
if (readyHandler) {
readyHandler();
}
};
},
applyCacheBuster: function(url) {
var tstamp = new Date().getTime(),
sep = url.indexOf('?') === -1 ? '?' : '&';
url = url + sep + "_dc=" + tstamp;
return url;
},
run: function() {
Microloader.init();
var manifest = Ext.manifest;
if (typeof manifest === "string") {
var extension = ".json",
url = manifest.indexOf(extension) === manifest.length - extension.length
? manifest
: manifest + ".json",
key = getStorageKey(url),
content = LocalStorage.retrieveAsset(key);
// Manifest found in local storage, use this for immediate boot except in PhantomJS environments for building.
if (content) {
//<debug>
_debug("Manifest file, '" + url + "', was found in Local Storage");
//</debug>
manifest = new Manifest({
url: url,
content: content,
cached: true
});
if (postProcessor) {
postProcessor(manifest);
}
Microloader.load(manifest);
// Manifest is not in local storage. Fetch it from the server
} else {
Boot.fetch(Microloader.applyCacheBuster(url), function (result) {
//<debug>
_debug("Manifest file was not found in Local Storage, loading: " + url);
//</debug>
manifest = new Manifest({
url: url,
content: result.content
});
manifest.cache();
if (postProcessor) {
postProcessor(manifest);
}
Microloader.load(manifest);
});
}
// Embedded Manifest into JS file
} else {
//<debug>
_debug("Manifest was embedded into application javascript file");
//</debug>
manifest = new Manifest({
content: manifest
});
Microloader.load(manifest);
}
},
/**
* @param {Manifest} manifest
*/
load: function (manifest) {
Microloader.urls = [];
Microloader.manifest = manifest;
Ext.manifest = Microloader.manifest.exportContent();
var assets = manifest.getAssets(),
cachedAssets = [],
asset, i, len, include, entry;
for (len = assets.length, i = 0; i < len; i++) {
asset = assets[i];
include = Microloader.filterAsset(asset);
if (include) {
// Asset is using the localStorage caching system
if (manifest.shouldCache() && asset.shouldCache()) {
// Asset already has content from localStorage, instantly seed that into boot
if (asset.content) {
//<debug>
_debug("Asset: " + asset.assetConfig.path + " was found in local storage. No remote load for this file");
//</debug>
entry = Boot.registerContent(asset.assetConfig.path, asset.type, asset.content);
if (entry.evaluated) {
_warn("Asset: " + asset.assetConfig.path + " was evaluated prior to local storage being consulted.");
}
//load via AJAX and seed content into Boot
} else {
//<debug>
_debug("Asset: " + asset.assetConfig.path + " was NOT found in local storage. Adding to load queue");
//</debug>
cachedAssets.push(asset);
}
}
Microloader.urls.push(asset.assetConfig.path);
Boot.assetConfig[asset.assetConfig.path] = Boot.apply({type: asset.type}, asset.assetConfig);
}
}
// If any assets are using the caching system and do not have local versions load them first via AJAX
if (cachedAssets.length > 0) {
Microloader.remainingCachedAssets = cachedAssets.length;
while (cachedAssets.length > 0) {
asset = cachedAssets.pop();
//<debug>
_debug("Preloading/Fetching Cached Assets from: " + asset.assetConfig.path);
//</debug>
Boot.fetch(asset.assetConfig.path, (function(asset) {
return function(result) {
Microloader.onCachedAssetLoaded(asset, result);
}
})(asset));
}
} else {
Microloader.onCachedAssetsReady();
}
},
// Load the asset and seed its content into Boot to be evaluated in sequence
onCachedAssetLoaded: function (asset, result) {
var checksum;
result = Microloader.parseResult(result);
Microloader.remainingCachedAssets--;
if (!result.error) {
checksum = Microloader.checksum(result.content, asset.assetConfig.hash);
if (!checksum) {
_warn("Cached Asset '" + asset.assetConfig.path + "' has failed checksum. This asset will be uncached for future loading");
// Un cache this asset so it is loaded next time
asset.uncache();
}
//<debug>
_debug("Checksum for Cached Asset: " + asset.assetConfig.path + " is " + checksum);
//</debug>
Boot.registerContent(asset.assetConfig.path, asset.type, result.content);
asset.updateContent(result.content);
asset.cache();
} else {
_warn("There was an error pre-loading the asset '" + asset.assetConfig.path + "'. This asset will be uncached for future loading");
// Un cache this asset so it is loaded next time
asset.uncache();
}
if (Microloader.remainingCachedAssets === 0) {
Microloader.onCachedAssetsReady();
}
},
onCachedAssetsReady: function(){
Boot.load({
url: Microloader.urls,
loadOrder: Microloader.manifest.loadOrder,
loadOrderMap: Microloader.manifest.loadOrderMap,
sequential: true,
success: Microloader.onAllAssetsReady,
failure: Microloader.onAllAssetsReady
});
},
onAllAssetsReady: function() {
_loaded = true;
Microloader.notify();
if (navigator.onLine !== false) {
//<debug>
_debug("Application is online, checking for updates");
//</debug>
Microloader.checkAllUpdates();
}
else {
//<debug>
_debug("Application is offline, adding online listener to check for updates");
//</debug>
if(window['addEventListener']) {
window.addEventListener('online', Microloader.checkAllUpdates, false);
}
}
},
onMicroloaderReady: function (listener) {
if (_loaded) {
listener();
} else {
_listeners.push(listener);
}
},
/**
* @private
*/
notify: function () {
//<debug>
_debug("notifying microloader ready listeners.");
//</debug>
var listener;
while((listener = _listeners.shift())) {
listener();
}
},
// Delta patches content
patch: function (content, delta) {
var output = [],
chunk, i, ln;
if (delta.length === 0) {
return content;
}
for (i = 0,ln = delta.length; i < ln; i++) {
chunk = delta[i];
if (typeof chunk === 'number') {
output.push(content.substring(chunk, chunk + delta[++i]));
}
else {
output.push(chunk);
}
}
return output.join('');
},
checkAllUpdates: function() {
//<debug>
_debug("Checking for All Updates");
//</debug>
if(window['removeEventListener']) {
window.removeEventListener('online', Microloader.checkAllUpdates, false);
}
if(_cache) {
Microloader.checkForAppCacheUpdate();
}
// Manifest came from a cached instance, check for updates
if (Microloader.manifest.fromCache) {
Microloader.checkForUpdates();
}
},
checkForAppCacheUpdate: function() {
//<debug>
_debug("Checking App Cache status");
//</debug>
if (_cache.status === _cache.UPDATEREADY || _cache.status === _cache.OBSOLETE) {
//<debug>
_debug("App Cache is already in an updated");
//</debug>
Microloader.appCacheState = 'updated';
} else if (_cache.status !== _cache.IDLE && _cache.status !== _cache.UNCACHED) {
//<debug>
_debug("App Cache is checking or downloading updates, adding listeners");
//</debug>
Microloader.appCacheState = 'checking';
_cache.addEventListener('error', Microloader.onAppCacheError);
_cache.addEventListener('noupdate', Microloader.onAppCacheNotUpdated);
_cache.addEventListener('cached', Microloader.onAppCacheNotUpdated);
_cache.addEventListener('updateready', Microloader.onAppCacheReady);
_cache.addEventListener('obsolete', Microloader.onAppCacheObsolete);
} else {
//<debug>
_debug("App Cache is current or uncached");
//</debug>
Microloader.appCacheState = 'current';
}
},
checkForUpdates: function() {
// Fetch the Latest Manifest from the server
//<debug>
_debug("Checking for updates at: " + Microloader.manifest.url);
//</debug>
Boot.fetch(Microloader.applyCacheBuster(Microloader.manifest.url), Microloader.onUpdatedManifestLoaded);
},
onAppCacheError: function(e) {
_warn(e.message);
Microloader.appCacheState = 'error';
Microloader.notifyUpdateReady();
},
onAppCacheReady: function() {
_cache.swapCache();
Microloader.appCacheUpdated();
},
onAppCacheObsolete: function() {
Microloader.appCacheUpdated();
},
appCacheUpdated: function() {
//<debug>
_debug("App Cache Updated");
//</debug>
Microloader.appCacheState = 'updated';
Microloader.notifyUpdateReady();
},
onAppCacheNotUpdated: function() {
//<debug>
_debug("App Cache Not Updated Callback");
//</debug>
Microloader.appCacheState = 'current';
Microloader.notifyUpdateReady();
},
filterAsset: function(asset) {
var cfg = (asset && asset.assetConfig) || {};
if(cfg.platform || cfg.exclude) {
return Boot.filterPlatform(cfg.platform, cfg.exclude);
}
return true;
},
onUpdatedManifestLoaded: function (result) {
result = Microloader.parseResult(result);
if (!result.error) {
var currentAssets, newAssets, currentAsset, newAsset, prop,
assets, deltas, deltaPath, include,
updatingAssets = [],
manifest = new Manifest({
url: Microloader.manifest.url,
content: result.content,
assetCache: false
});
Microloader.remainingUpdatingAssets = 0;
Microloader.updatedAssets = [];
Microloader.removedAssets = [];
Microloader.updatedManifest = null;
Microloader.updatedAssetsReady = false;
// If the updated manifest has turned off caching we need to clear out all local storage
// and trigger a appupdate as all content is now uncached
if (!manifest.shouldCache()) {
//<debug>
_debug("New Manifest has caching disabled, clearing out any private storage");
//</debug>
Microloader.updatedManifest = manifest;
LocalStorage.clearAllPrivate(manifest);
Microloader.onAllUpdatedAssetsReady();
return;
}
// Manifest itself has changed
if (!Microloader.manifest.is(manifest)) {
Microloader.updatedManifest = manifest;
currentAssets = Microloader.manifest.getAssets();
newAssets = manifest.getAssets();
// Look through new assets for assets that do not exist or assets that have different versions
for (prop in newAssets) {
newAsset = newAssets[prop];
currentAsset = Microloader.manifest.getAsset(newAsset.assetConfig.path);
include = Microloader.filterAsset(newAsset);
if (include && (!currentAsset || (newAsset.shouldCache() && (!currentAsset.is(newAsset))))) {
//<debug>
_debug("New/Updated Version of Asset: " + newAsset.assetConfig.path + " was found in new manifest");
//</debug>
updatingAssets.push({_new: newAsset, _current: currentAsset});
}
}
// Look through current assets for stale/old assets that have been removed
for (prop in currentAssets) {
currentAsset = currentAssets[prop];
newAsset = manifest.getAsset(currentAsset.assetConfig.path);
//New version of this asset has been filtered out
include = !Microloader.filterAsset(newAsset);
if (!include || !newAsset || (currentAsset.shouldCache() && !newAsset.shouldCache())) {
//<debug>
_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");
//</debug>
Microloader.removedAssets.push(currentAsset);
}
}
// Loop through all assets that need updating
if (updatingAssets.length > 0) {
Microloader.remainingUpdatingAssets = updatingAssets.length;
while (updatingAssets.length > 0) {
assets = updatingAssets.pop();
newAsset = assets._new;
currentAsset = assets._current;
// Full Updates will simply download the file and replace its current content
if (newAsset.assetConfig.update === "full" || !currentAsset) {
//<debug>
if (newAsset.assetConfig.update === "delta") {
_debug("Delta updated asset found without current asset available: " + newAsset.assetConfig.path + " fetching full file");
} else {
_debug("Full update found for: " + newAsset.assetConfig.path + " fetching");
}
//</debug>
// Load the asset and cache its its content into Boot to be evaluated in sequence
Boot.fetch(newAsset.assetConfig.path, (function (asset) {
return function (result) {
Microloader.onFullAssetUpdateLoaded(asset, result)
};
}(newAsset))
);
// Delta updates will be given a delta patch
} else if (newAsset.assetConfig.update === "delta") {
deltas = manifest.deltas;
deltaPath = deltas + "/" + newAsset.assetConfig.path + "/" + currentAsset.assetConfig.hash + ".json";
// Fetch the Delta Patch and update the contents of the asset
//<debug>
_debug("Delta update found for: " + newAsset.assetConfig.path + " fetching");
//</debug>
Boot.fetch(deltaPath,
(function (asset, oldAsset) {
return function (result) {
Microloader.onDeltaAssetUpdateLoaded(asset, oldAsset, result)
};
}(newAsset, currentAsset))
);
}
}
} else {
//<debug>
_debug("No Assets needed updating");
//</debug>
Microloader.onAllUpdatedAssetsReady();
}
} else {
//<debug>
_debug("Manifest files have matching hash's");
//</debug>
Microloader.onAllUpdatedAssetsReady();
}
} else {
_warn("Error loading manifest file to check for updates");
Microloader.onAllUpdatedAssetsReady();
}
},
onFullAssetUpdateLoaded: function(asset, result) {
var checksum;
result = Microloader.parseResult(result);
Microloader.remainingUpdatingAssets--;
if (!result.error) {
checksum = Microloader.checksum(result.content, asset.assetConfig.hash);
//<debug>
_debug("Checksum for Full asset: " + asset.assetConfig.path + " is " + checksum);
//</debug>
if (!checksum) {
//<debug>
_debug("Full Update Asset: " + asset.assetConfig.path + " has failed checksum. This asset will be uncached for future loading");
//</debug>
// uncache this asset as there is a new version somewhere that has not been loaded.
asset.uncache();
} else {
asset.updateContent(result.content);
Microloader.updatedAssets.push(asset);
}
} else {
//<debug>
_debug("Error loading file at" + asset.assetConfig.path + ". This asset will be uncached for future loading");
//</debug>
// uncache this asset as there is a new version somewhere that has not been loaded.
asset.uncache();
}
if (Microloader.remainingUpdatingAssets === 0) {
Microloader.onAllUpdatedAssetsReady();
}
},
onDeltaAssetUpdateLoaded: function(asset, oldAsset, result) {
var json, checksum, content;
result = Microloader.parseResult(result);
Microloader.remainingUpdatingAssets--;
if (!result.error) {
//<debug>
_debug("Delta patch loaded successfully, patching content");
//</debug>
try {
json = JSON.parse(result.content);
content = Microloader.patch(oldAsset.content, json);
checksum = Microloader.checksum(content, asset.assetConfig.hash);
//<debug>
_debug("Checksum for Delta Patched asset: " + asset.assetConfig.path + " is " + checksum);
//</debug>
if (!checksum) {
//<debug>
_debug("Delta Update Asset: " + asset.assetConfig.path + " has failed checksum. This asset will be uncached for future loading");
//</debug>
// uncache this asset as there is a new version somewhere that has not been loaded.
asset.uncache();
} else {
asset.updateContent(content);
Microloader.updatedAssets.push(asset);
}
} catch (e) {
_warn("Error parsing delta patch for " + asset.assetConfig.path + " with hash " + oldAsset.assetConfig.hash + " . This asset will be uncached for future loading");
// uncache this asset as there is a new version somewhere that has not been loaded.
asset.uncache();
}
} else {
_warn("Error loading delta patch for " + asset.assetConfig.path + " with hash " + oldAsset.assetConfig.hash + " . This asset will be uncached for future loading");
// uncache this asset as there is a new version somewhere that has not been loaded.
asset.uncache();
}
if (Microloader.remainingUpdatingAssets === 0) {
Microloader.onAllUpdatedAssetsReady();
}
},
//TODO: Make this all transaction based to allow for reverting if quota is exceeded
onAllUpdatedAssetsReady: function() {
var asset;
Microloader.updatedAssetsReady = true;
if (Microloader.updatedManifest) {
while (Microloader.removedAssets.length > 0) {
asset = Microloader.removedAssets.pop();
//<debug>
_debug("Asset: " + asset.assetConfig.path + " was removed, un-caching");
//</debug>
asset.uncache();
}
if (Microloader.updatedManifest) {
//<debug>
_debug("Manifest was updated, re-caching");
//</debug>
Microloader.updatedManifest.cache();
}
while (Microloader.updatedAssets.length > 0) {
asset = Microloader.updatedAssets.pop();
//<debug>
_debug("Asset: " + asset.assetConfig.path + " was updated, re-caching");
//</debug>
asset.cache();
}
}
Microloader.notifyUpdateReady();
},
notifyUpdateReady: function () {
if (Microloader.appCacheState !== 'checking' && Microloader.updatedAssetsReady) {
if (Microloader.appCacheState === 'updated' || Microloader.updatedManifest) {
//<debug>
_debug("There was an update here you will want to reload the app, trigger an event");
//</debug>
Microloader.appUpdate = {
updated: true,
app: Microloader.appCacheState === 'updated',
manifest: Microloader.updatedManifest && Microloader.updatedManifest.exportContent()
};
Microloader.fireAppUpdate();
}
//<debug>
else {
_debug("AppCache and LocalStorage Cache are current, no updating needed");
Microloader.appUpdate = {};
}
//</debug>
}
},
fireAppUpdate: function() {
if (Ext.GlobalEvents) {
// We defer dispatching this event slightly in order to let the application finish loading
// as we are still very early in the lifecycle
Ext.defer(function() {
Ext.GlobalEvents.fireEvent('appupdate', Microloader.appUpdate);
}, 100);
}
},
checksum: function(content, hash) {
if(!content || !hash) {
return false;
}
var passed = true,
hashLn = hash.length,
checksumType = content.substring(0, 1);
if (checksumType == '/') {
if (content.substring(2, hashLn + 2) !== hash) {
passed = false;
}
} else if (checksumType == 'f') {
if (content.substring(10, hashLn + 10) !== hash) {
passed = false;
}
} else if (checksumType == '.') {
if (content.substring(1, hashLn + 1) !== hash) {
passed = false;
}
}
return passed;
},
parseResult: function(result) {
var rst = {};
if ((result.exception || result.status === 0) && !Boot.env.phantom) {
rst.error = true;
} else if ((result.status >= 200 && result.status < 300) || result.status === 304
|| Boot.env.phantom
|| (result.status === 0 && result.content.length > 0)
) {
rst.content = result.content;
} else {
rst.error = true;
}
return rst;
}
};
return Microloader;
}());
/**
* @type {String/Object}
*/
Ext.manifest = Ext.manifest || "bootstrap";
Ext.Microloader.run();