<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js">// @tag foundation,core
|
// @require ClassManager.js
|
// @define Ext.Loader
|
|
<span id='Ext-Loader'>/**
|
</span> * @author Jacky Nguyen <jacky@sencha.com>
|
* @docauthor Jacky Nguyen <jacky@sencha.com>
|
* @class Ext.Loader
|
*
|
* Ext.Loader is the heart of the new dynamic dependency loading capability in Ext JS 4+. It is most commonly used
|
* via the {@link Ext#require} shorthand. Ext.Loader supports both asynchronous and synchronous loading
|
* approaches, and leverage their advantages for the best development flow. We'll discuss about the pros and cons of each approach:
|
*
|
* # Asynchronous Loading #
|
*
|
* - Advantages:
|
* + Cross-domain
|
* + No web server needed: you can run the application via the file system protocol (i.e: `file://path/to/your/index
|
* .html`)
|
* + Best possible debugging experience: error messages come with the exact file name and line number
|
*
|
* - Disadvantages:
|
* + Dependencies need to be specified before-hand
|
*
|
* ### Method 1: Explicitly include what you need: ###
|
*
|
* // Syntax
|
* Ext.require({String/Array} expressions);
|
*
|
* // Example: Single alias
|
* Ext.require('widget.window');
|
*
|
* // Example: Single class name
|
* Ext.require('Ext.window.Window');
|
*
|
* // Example: Multiple aliases / class names mix
|
* Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);
|
*
|
* // Wildcards
|
* Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);
|
*
|
* ### Method 2: Explicitly exclude what you don't need: ###
|
*
|
* // Syntax: Note that it must be in this chaining format.
|
* Ext.exclude({String/Array} expressions)
|
* .require({String/Array} expressions);
|
*
|
* // Include everything except Ext.data.*
|
* Ext.exclude('Ext.data.*').require('*');
|
*
|
* // Include all widgets except widget.checkbox*,
|
* // which will match widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.
|
* Ext.exclude('widget.checkbox*').require('widget.*');
|
*
|
* # Synchronous Loading on Demand #
|
*
|
* - Advantages:
|
* + There's no need to specify dependencies before-hand, which is always the convenience of including ext-all.js
|
* before
|
*
|
* - Disadvantages:
|
* + Not as good debugging experience since file name won't be shown (except in Firebug at the moment)
|
* + Must be from the same domain due to XHR restriction
|
* + Need a web server, same reason as above
|
*
|
* There's one simple rule to follow: Instantiate everything with Ext.create instead of the `new` keyword
|
*
|
* Ext.create('widget.window', { ... }); // Instead of new Ext.window.Window({...});
|
*
|
* Ext.create('Ext.window.Window', {}); // Same as above, using full class name instead of alias
|
*
|
* Ext.widget('window', {}); // Same as above, all you need is the traditional `xtype`
|
*
|
* Behind the scene, {@link Ext.ClassManager} will automatically check whether the given class name / alias has already
|
* existed on the page. If it's not, Ext.Loader will immediately switch itself to synchronous mode and automatic load the given
|
* class and all its dependencies.
|
*
|
* # Hybrid Loading - The Best of Both Worlds #
|
*
|
* It has all the advantages combined from asynchronous and synchronous loading. The development flow is simple:
|
*
|
* ### Step 1: Start writing your application using synchronous approach.
|
*
|
* Ext.Loader will automatically fetch all dependencies on demand as they're needed during run-time. For example:
|
*
|
* Ext.onReady(function(){
|
* var window = Ext.widget('window', {
|
* width: 500,
|
* height: 300,
|
* layout: {
|
* type: 'border',
|
* padding: 5
|
* },
|
* title: 'Hello Dialog',
|
* items: [{
|
* title: 'Navigation',
|
* collapsible: true,
|
* region: 'west',
|
* width: 200,
|
* html: 'Hello',
|
* split: true
|
* }, {
|
* title: 'TabPanel',
|
* region: 'center'
|
* }]
|
* });
|
*
|
* window.show();
|
* })
|
*
|
* ### Step 2: Along the way, when you need better debugging ability, watch the console for warnings like these: ###
|
*
|
* [Ext.Loader] Synchronously loading 'Ext.window.Window'; consider adding Ext.require('Ext.window.Window') before your application's code
|
* ClassManager.js:432
|
* [Ext.Loader] Synchronously loading 'Ext.layout.container.Border'; consider adding Ext.require('Ext.layout.container.Border') before your application's code
|
*
|
* Simply copy and paste the suggested code above `Ext.onReady`, i.e:
|
*
|
* Ext.require('Ext.window.Window');
|
* Ext.require('Ext.layout.container.Border');
|
*
|
* Ext.onReady(...);
|
*
|
* Everything should now load via asynchronous mode.
|
*
|
* # Deployment #
|
*
|
* It's important to note that dynamic loading should only be used during development on your local machines.
|
* During production, all dependencies should be combined into one single JavaScript file. Ext.Loader makes
|
* the whole process of transitioning from / to between development / maintenance and production as easy as
|
* possible. Internally {@link Ext.Loader#history Ext.Loader.history} maintains the list of all dependencies your application
|
* needs in the exact loading sequence. It's as simple as concatenating all files in this array into one,
|
* then include it on top of your application.
|
*
|
* This process will be automated with Sencha Command, to be released and documented towards Ext JS 4 Final.
|
*
|
* @singleton
|
*/
|
|
Ext.Loader = new function() {
|
var Loader = this,
|
Manager = Ext.ClassManager,
|
Class = Ext.Class,
|
flexSetter = Ext.Function.flexSetter,
|
alias = Ext.Function.alias,
|
pass = Ext.Function.pass,
|
defer = Ext.Function.defer,
|
arrayErase = Ext.Array.erase,
|
//<if nonBrowser>
|
isNonBrowser = typeof window == 'undefined',
|
isNodeJS = isNonBrowser && (typeof require == 'function'),
|
isJsdb = isNonBrowser && typeof system != 'undefined' && system.program.search(/jsdb/) !== -1,
|
isPhantomJS = (typeof phantom != 'undefined' && phantom.fs),
|
//</if>
|
dependencyProperties = ['extend', 'mixins', 'requires'],
|
isInHistory = {},
|
history = [],
|
slashDotSlashRe = /\/\.\//g,
|
dotRe = /\./g,
|
setPathCount = 0;
|
|
Ext.apply(Loader, {
|
|
<span id='Ext-Loader-property-isInHistory'> /**
|
</span> * @private
|
*/
|
isInHistory: isInHistory,
|
|
<span id='Ext-Loader-property-history'> /**
|
</span> * An array of class names to keep track of the dependency loading order.
|
* This is not guaranteed to be the same everytime due to the asynchronous
|
* nature of the Loader.
|
*
|
* @property {Array} history
|
*/
|
history: history,
|
|
<span id='Ext-Loader-property-config'> /**
|
</span> * Configuration
|
* @private
|
*/
|
config: {
|
<span id='Ext-Loader-cfg-enabled'> /**
|
</span> * @cfg {Boolean} enabled
|
* Whether or not to enable the dynamic dependency loading feature.
|
*/
|
enabled: false,
|
|
<span id='Ext-Loader-cfg-scriptChainDelay'> /**
|
</span> * @cfg {Boolean} scriptChainDelay
|
* millisecond delay between asynchronous script injection (prevents stack overflow on some user agents)
|
* 'false' disables delay but potentially increases stack load.
|
*/
|
scriptChainDelay : false,
|
|
<span id='Ext-Loader-cfg-disableCaching'> /**
|
</span> * @cfg {Boolean} disableCaching
|
* Appends current timestamp to script files to prevent caching.
|
*/
|
disableCaching: true,
|
|
<span id='Ext-Loader-cfg-disableCachingParam'> /**
|
</span> * @cfg {String} disableCachingParam
|
* The get parameter name for the cache buster's timestamp.
|
*/
|
disableCachingParam: '_dc',
|
|
<span id='Ext-Loader-cfg-garbageCollect'> /**
|
</span> * @cfg {Boolean} garbageCollect
|
* True to prepare an asynchronous script tag for garbage collection (effective only
|
* if {@link #preserveScripts preserveScripts} is false)
|
*/
|
garbageCollect : false,
|
|
<span id='Ext-Loader-cfg-paths'> /**
|
</span> * @cfg {Object} paths
|
* The mapping from namespaces to file paths
|
*
|
* {
|
* 'Ext': '.', // This is set by default, Ext.layout.container.Container will be
|
* // loaded from ./layout/Container.js
|
*
|
* 'My': './src/my_own_folder' // My.layout.Container will be loaded from
|
* // ./src/my_own_folder/layout/Container.js
|
* }
|
*
|
* Note that all relative paths are relative to the current HTML document.
|
* If not being specified, for example, <code>Other.awesome.Class</code>
|
* will simply be loaded from <code>./Other/awesome/Class.js</code>
|
*/
|
paths: {
|
'Ext': '.'
|
},
|
|
<span id='Ext-Loader-cfg-preserveScripts'> /**
|
</span> * @cfg {Boolean} preserveScripts
|
* False to remove and optionally {@link #garbageCollect garbage-collect} asynchronously loaded scripts,
|
* True to retain script element for browser debugger compatibility and improved load performance.
|
*/
|
preserveScripts : true,
|
|
<span id='Ext-Loader-cfg-scriptCharset'> /**
|
</span> * @cfg {String} scriptCharset
|
* Optional charset to specify encoding of dynamic script content.
|
*/
|
scriptCharset : undefined
|
},
|
|
<span id='Ext-Loader-method-setConfig'> /**
|
</span> * Set the configuration for the loader. This should be called right after ext-(debug).js
|
* is included in the page, and before Ext.onReady. i.e:
|
*
|
* <script type="text/javascript" src="ext-core-debug.js"></script>
|
* <script type="text/javascript">
|
* Ext.Loader.setConfig({
|
* enabled: true,
|
* paths: {
|
* 'My': 'my_own_path'
|
* }
|
* });
|
* </script>
|
* <script type="text/javascript">
|
* Ext.require(...);
|
*
|
* Ext.onReady(function() {
|
* // application code here
|
* });
|
* </script>
|
*
|
* Refer to config options of {@link Ext.Loader} for the list of possible properties
|
*
|
* @param {Object} config The config object to override the default values
|
* @return {Ext.Loader} this
|
*/
|
setConfig: function(name, value) {
|
if (Ext.isObject(name) && arguments.length === 1) {
|
Ext.merge(Loader.config, name);
|
|
if ('paths' in name) {
|
Ext.app.collectNamespaces(name.paths);
|
}
|
}
|
else {
|
Loader.config[name] = (Ext.isObject(value)) ? Ext.merge(Loader.config[name], value) : value;
|
|
if (name === 'paths') {
|
Ext.app.collectNamespaces(value);
|
}
|
}
|
|
return Loader;
|
},
|
|
<span id='Ext-Loader-method-getConfig'> /**
|
</span> * Get the config value corresponding to the specified name. If no name is given, will return the config object
|
* @param {String} name The config property name
|
* @return {Object}
|
*/
|
getConfig: function(name) {
|
if (name) {
|
return Loader.config[name];
|
}
|
|
return Loader.config;
|
},
|
|
<span id='Ext-Loader-method-setPath'> /**
|
</span> * Sets the path of a namespace.
|
* For Example:
|
*
|
* Ext.Loader.setPath('Ext', '.');
|
*
|
* @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}
|
* @param {String} [path] See {@link Ext.Function#flexSetter flexSetter}
|
* @return {Ext.Loader} this
|
* @method
|
*/
|
setPath: flexSetter(function(name, path) {
|
Loader.config.paths[name] = path;
|
Ext.app.namespaces[name] = true;
|
setPathCount++;
|
|
return Loader;
|
}),
|
|
<span id='Ext-Loader-method-addClassPathMappings'> /**
|
</span> * Sets a batch of path entries
|
*
|
* @param {Object } paths a set of className: path mappings
|
* @return {Ext.Loader} this
|
*/
|
addClassPathMappings: function(paths) {
|
var name;
|
|
if(setPathCount == 0){
|
Loader.config.paths = paths;
|
} else {
|
for(name in paths){
|
Loader.config.paths[name] = paths[name];
|
}
|
}
|
setPathCount++;
|
return Loader;
|
},
|
|
<span id='Ext-Loader-method-getPath'> /**
|
</span> * Translates a className to a file path by adding the
|
* the proper prefix and converting the .'s to /'s. For example:
|
*
|
* Ext.Loader.setPath('My', '/path/to/My');
|
*
|
* alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'
|
*
|
* Note that the deeper namespace levels, if explicitly set, are always resolved first. For example:
|
*
|
* Ext.Loader.setPath({
|
* 'My': '/path/to/lib',
|
* 'My.awesome': '/other/path/for/awesome/stuff',
|
* 'My.awesome.more': '/more/awesome/path'
|
* });
|
*
|
* alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'
|
*
|
* alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'
|
*
|
* alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'
|
*
|
* alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'
|
*
|
* @param {String} className
|
* @return {String} path
|
*/
|
getPath: function(className) {
|
var path = '',
|
paths = Loader.config.paths,
|
prefix = Loader.getPrefix(className);
|
|
if (prefix.length > 0) {
|
if (prefix === className) {
|
return paths[prefix];
|
}
|
|
path = paths[prefix];
|
className = className.substring(prefix.length + 1);
|
}
|
|
if (path.length > 0) {
|
path += '/';
|
}
|
|
return path.replace(slashDotSlashRe, '/') + className.replace(dotRe, "/") + '.js';
|
},
|
|
<span id='Ext-Loader-method-getPrefix'> /**
|
</span> * @private
|
* @param {String} className
|
*/
|
getPrefix: function(className) {
|
var paths = Loader.config.paths,
|
prefix, deepestPrefix = '';
|
|
if (paths.hasOwnProperty(className)) {
|
return className;
|
}
|
|
for (prefix in paths) {
|
if (paths.hasOwnProperty(prefix) && prefix + '.' === className.substring(0, prefix.length + 1)) {
|
if (prefix.length > deepestPrefix.length) {
|
deepestPrefix = prefix;
|
}
|
}
|
}
|
|
return deepestPrefix;
|
},
|
|
<span id='Ext-Loader-method-isAClassNameWithAKnownPrefix'> /**
|
</span> * @private
|
* @param {String} className
|
*/
|
isAClassNameWithAKnownPrefix: function(className) {
|
var prefix = Loader.getPrefix(className);
|
|
// we can only say it's really a class if className is not equal to any known namespace
|
return prefix !== '' && prefix !== className;
|
},
|
|
<span id='Ext-Loader-method-require'> /**
|
</span> * Loads all classes by the given names and all their direct dependencies; optionally executes
|
* the given callback function when finishes, within the optional scope.
|
*
|
* {@link Ext#require} is alias for {@link Ext.Loader#require}.
|
*
|
* @param {String/Array} expressions Can either be a string or an array of string
|
* @param {Function} fn (Optional) The callback function
|
* @param {Object} scope (Optional) The execution scope (`this`) of the callback function
|
* @param {String/Array} excludes (Optional) Classes to be excluded, useful when being used with expressions
|
*/
|
require: function(expressions, fn, scope, excludes) {
|
if (fn) {
|
fn.call(scope);
|
}
|
},
|
|
<span id='Ext-Loader-method-syncRequire'> /**
|
</span> * Synchronously loads all classes by the given names and all their direct dependencies; optionally
|
* executes the given callback function when finishes, within the optional scope.
|
*
|
* {@link Ext#syncRequire} is alias for {@link Ext.Loader#syncRequire}.
|
*
|
* @param {String/Array} expressions Can either be a string or an array of string
|
* @param {Function} fn (Optional) The callback function
|
* @param {Object} scope (Optional) The execution scope (`this`) of the callback function
|
* @param {String/Array} excludes (Optional) Classes to be excluded, useful when being used with expressions
|
*/
|
syncRequire: function() {},
|
|
<span id='Ext-Loader-method-exclude'> /**
|
</span> * Explicitly exclude files from being loaded. Useful when used in conjunction with a broad include expression.
|
* Can be chained with more `require` and `exclude` methods, eg:
|
*
|
* Ext.exclude('Ext.data.*').require('*');
|
*
|
* Ext.exclude('widget.button*').require('widget.*');
|
*
|
* {@link Ext#exclude} is alias for {@link Ext.Loader#exclude}.
|
*
|
* @param {Array} excludes
|
* @return {Object} object contains `require` method for chaining
|
*/
|
exclude: function(excludes) {
|
return {
|
require: function(expressions, fn, scope) {
|
return Loader.require(expressions, fn, scope, excludes);
|
},
|
|
syncRequire: function(expressions, fn, scope) {
|
return Loader.syncRequire(expressions, fn, scope, excludes);
|
}
|
};
|
},
|
|
<span id='Ext-Loader-method-onReady'> /**
|
</span> * Add a new listener to be executed when all required scripts are fully loaded
|
*
|
* @param {Function} fn The function callback to be executed
|
* @param {Object} scope The execution scope (<code>this</code>) of the callback function
|
* @param {Boolean} withDomReady Whether or not to wait for document dom ready as well
|
*/
|
onReady: function(fn, scope, withDomReady, options) {
|
var oldFn;
|
|
if (withDomReady !== false && Ext.onDocumentReady) {
|
oldFn = fn;
|
|
fn = function() {
|
Ext.onDocumentReady(oldFn, scope, options);
|
};
|
}
|
|
fn.call(scope);
|
}
|
});
|
|
//<feature classSystem.loader>
|
var queue = [],
|
isClassFileLoaded = {},
|
isFileLoaded = {},
|
classNameToFilePathMap = {},
|
scriptElements = {},
|
readyListeners = [],
|
usedClasses = [],
|
requiresMap = {},
|
comparePriority = function(listenerA, listenerB) {
|
return listenerB.priority - listenerA.priority;
|
};
|
|
Ext.apply(Loader, {
|
<span id='Ext-Loader-property-documentHead'> /**
|
</span> * @private
|
*/
|
documentHead: typeof document != 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
|
|
<span id='Ext-Loader-property-isLoading'> /**
|
</span> * Flag indicating whether there are still files being loaded
|
* @private
|
*/
|
isLoading: false,
|
|
<span id='Ext-Loader-property-queue'> /**
|
</span> * Maintain the queue for all dependencies. Each item in the array is an object of the format:
|
*
|
* {
|
* requires: [...], // The required classes for this queue item
|
* callback: function() { ... } // The function to execute when all classes specified in requires exist
|
* }
|
*
|
* @private
|
*/
|
queue: queue,
|
|
<span id='Ext-Loader-property-isClassFileLoaded'> /**
|
</span> * Maintain the list of files that have already been handled so that they never get double-loaded
|
* @private
|
*/
|
isClassFileLoaded: isClassFileLoaded,
|
|
<span id='Ext-Loader-property-isFileLoaded'> /**
|
</span> * @private
|
*/
|
isFileLoaded: isFileLoaded,
|
|
<span id='Ext-Loader-property-readyListeners'> /**
|
</span> * Maintain the list of listeners to execute when all required scripts are fully loaded
|
* @private
|
*/
|
readyListeners: readyListeners,
|
|
<span id='Ext-Loader-property-optionalRequires'> /**
|
</span> * Contains classes referenced in `uses` properties.
|
* @private
|
*/
|
optionalRequires: usedClasses,
|
|
<span id='Ext-Loader-property-requiresMap'> /**
|
</span> * Map of fully qualified class names to an array of dependent classes.
|
* @private
|
*/
|
requiresMap: requiresMap,
|
|
<span id='Ext-Loader-property-numPendingFiles'> /**
|
</span> * @private
|
*/
|
numPendingFiles: 0,
|
|
<span id='Ext-Loader-property-numLoadedFiles'> /**
|
</span> * @private
|
*/
|
numLoadedFiles: 0,
|
|
<span id='Ext-Loader-property-hasFileLoadError'> /** @private */
|
</span> hasFileLoadError: false,
|
|
<span id='Ext-Loader-property-classNameToFilePathMap'> /**
|
</span> * @private
|
*/
|
classNameToFilePathMap: classNameToFilePathMap,
|
|
<span id='Ext-Loader-property-scriptsLoading'> /**
|
</span> * The number of scripts loading via loadScript.
|
* @private
|
*/
|
scriptsLoading: 0,
|
|
<span id='Ext-Loader-property-syncModeEnabled'> /**
|
</span> * @private
|
*/
|
syncModeEnabled: false,
|
|
scriptElements: scriptElements,
|
|
<span id='Ext-Loader-method-refreshQueue'> /**
|
</span> * Refresh all items in the queue. If all dependencies for an item exist during looping,
|
* it will execute the callback and call refreshQueue again. Triggers onReady when the queue is
|
* empty
|
* @private
|
*/
|
refreshQueue: function() {
|
var ln = queue.length,
|
i, item, j, requires;
|
|
// When the queue of loading classes reaches zero, trigger readiness
|
|
if (!ln && !Loader.scriptsLoading) {
|
return Loader.triggerReady();
|
}
|
|
for (i = 0; i < ln; i++) {
|
item = queue[i];
|
|
if (item) {
|
requires = item.requires;
|
|
// Don't bother checking when the number of files loaded
|
// is still less than the array length
|
if (requires.length > Loader.numLoadedFiles) {
|
continue;
|
}
|
|
// Remove any required classes that are loaded
|
for (j = 0; j < requires.length; ) {
|
if (Manager.isCreated(requires[j])) {
|
// Take out from the queue
|
arrayErase(requires, j, 1);
|
}
|
else {
|
j++;
|
}
|
}
|
|
// If we've ended up with no required classes, call the callback
|
if (item.requires.length === 0) {
|
arrayErase(queue, i, 1);
|
item.callback.call(item.scope);
|
Loader.refreshQueue();
|
break;
|
}
|
}
|
}
|
|
return Loader;
|
},
|
|
<span id='Ext-Loader-method-injectScriptElement'> /**
|
</span> * Inject a script element to document's head, call onLoad and onError accordingly
|
* @private
|
*/
|
injectScriptElement: function(url, onLoad, onError, scope, charset) {
|
var script = document.createElement('script'),
|
dispatched = false,
|
config = Loader.config,
|
onLoadFn = function() {
|
|
if(!dispatched) {
|
dispatched = true;
|
script.onload = script.onreadystatechange = script.onerror = null;
|
if (typeof config.scriptChainDelay == 'number') {
|
//free the stack (and defer the next script)
|
defer(onLoad, config.scriptChainDelay, scope);
|
} else {
|
onLoad.call(scope);
|
}
|
Loader.cleanupScriptElement(script, config.preserveScripts === false, config.garbageCollect);
|
}
|
|
},
|
onErrorFn = function(arg) {
|
defer(onError, 1, scope); //free the stack
|
Loader.cleanupScriptElement(script, config.preserveScripts === false, config.garbageCollect);
|
};
|
|
script.type = 'text/javascript';
|
script.onerror = onErrorFn;
|
charset = charset || config.scriptCharset;
|
if (charset) {
|
script.charset = charset;
|
}
|
|
/*
|
* IE9 Standards mode (and others) SHOULD follow the load event only
|
* (Note: IE9 supports both onload AND readystatechange events)
|
*/
|
if ('addEventListener' in script ) {
|
script.onload = onLoadFn;
|
} else if ('readyState' in script) { // for <IE9 Compatability
|
script.onreadystatechange = function() {
|
if ( this.readyState == 'loaded' || this.readyState == 'complete' ) {
|
onLoadFn();
|
}
|
};
|
} else {
|
script.onload = onLoadFn;
|
}
|
|
script.src = url;
|
(Loader.documentHead || document.getElementsByTagName('head')[0]).appendChild(script);
|
|
return script;
|
},
|
|
<span id='Ext-Loader-method-removeScriptElement'> /**
|
</span> * @private
|
*/
|
removeScriptElement: function(url) {
|
if (scriptElements[url]) {
|
Loader.cleanupScriptElement(scriptElements[url], true, !!Loader.getConfig('garbageCollect'));
|
delete scriptElements[url];
|
}
|
|
return Loader;
|
},
|
|
<span id='Ext-Loader-method-cleanupScriptElement'> /**
|
</span> * @private
|
*/
|
cleanupScriptElement: function(script, remove, collect) {
|
var prop;
|
script.onload = script.onreadystatechange = script.onerror = null;
|
if (remove) {
|
Ext.removeNode(script); // Remove, since its useless now
|
if (collect) {
|
for (prop in script) {
|
try {
|
if (prop != 'src') {
|
// If we set the src property to null IE
|
// will try and request a script at './null'
|
script[prop] = null;
|
}
|
delete script[prop]; // and prepare for GC
|
} catch (cleanEx) {
|
//ignore
|
}
|
}
|
}
|
}
|
|
return Loader;
|
},
|
|
<span id='Ext-Loader-method-loadScript'> /**
|
</span> * Loads the specified script URL and calls the supplied callbacks. If this method
|
* is called before {@link Ext#isReady}, the script's load will delay the transition
|
* to ready. This can be used to load arbitrary scripts that may contain further
|
* {@link Ext#require Ext.require} calls.
|
*
|
* @param {Object/String} options The options object or simply the URL to load.
|
* @param {String} options.url The URL from which to load the script.
|
* @param {Function} [options.onLoad] The callback to call on successful load.
|
* @param {Function} [options.onError] The callback to call on failure to load.
|
* @param {Object} [options.scope] The scope (`this`) for the supplied callbacks.
|
*/
|
loadScript: function (options) {
|
var config = Loader.getConfig(),
|
isString = typeof options == 'string',
|
url = isString ? options : options.url,
|
onError = !isString && options.onError,
|
onLoad = !isString && options.onLoad,
|
scope = !isString && options.scope,
|
onScriptError = function() {
|
Loader.numPendingFiles--;
|
Loader.scriptsLoading--;
|
|
if (onError) {
|
onError.call(scope, "Failed loading '" + url + "', please verify that the file exists");
|
}
|
|
if (Loader.numPendingFiles + Loader.scriptsLoading === 0) {
|
Loader.refreshQueue();
|
}
|
},
|
onScriptLoad = function () {
|
Loader.numPendingFiles--;
|
Loader.scriptsLoading--;
|
|
if (onLoad) {
|
onLoad.call(scope);
|
}
|
|
if (Loader.numPendingFiles + Loader.scriptsLoading === 0) {
|
Loader.refreshQueue();
|
}
|
},
|
src;
|
|
Loader.isLoading = true;
|
Loader.numPendingFiles++;
|
Loader.scriptsLoading++;
|
|
src = config.disableCaching ?
|
(url + '?' + config.disableCachingParam + '=' + Ext.Date.now()) : url;
|
|
scriptElements[url] = Loader.injectScriptElement(src, onScriptLoad, onScriptError);
|
},
|
|
<span id='Ext-Loader-method-loadScriptFile'> /**
|
</span> * Load a script file, supports both asynchronous and synchronous approaches
|
* @private
|
*/
|
loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
|
if (isFileLoaded[url]) {
|
return Loader;
|
}
|
|
var config = Loader.getConfig(),
|
noCacheUrl = url + (config.disableCaching ? ('?' + config.disableCachingParam + '=' + Ext.Date.now()) : ''),
|
isCrossOriginRestricted = false,
|
xhr, status, onScriptError,
|
debugSourceURL = "";
|
|
scope = scope || Loader;
|
|
Loader.isLoading = true;
|
|
if (!synchronous) {
|
onScriptError = function() {
|
//<debug error>
|
onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
|
//</debug>
|
};
|
|
scriptElements[url] = Loader.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
|
} else {
|
if (typeof XMLHttpRequest != 'undefined') {
|
xhr = new XMLHttpRequest();
|
} else {
|
xhr = new ActiveXObject('Microsoft.XMLHTTP');
|
}
|
|
try {
|
xhr.open('GET', noCacheUrl, false);
|
xhr.send(null);
|
} catch (e) {
|
isCrossOriginRestricted = true;
|
}
|
|
status = (xhr.status === 1223) ? 204 :
|
(xhr.status === 0 && ((self.location || {}).protocol == 'file:' || (self.location || {}).protocol == 'ionp:')) ? 200 : xhr.status;
|
|
isCrossOriginRestricted = isCrossOriginRestricted || (status === 0);
|
|
if (isCrossOriginRestricted
|
//<if isNonBrowser>
|
&& !isPhantomJS
|
//</if>
|
) {
|
//<debug error>
|
onError.call(Loader, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
|
"being loaded from a different domain or from the local file system whereby cross origin " +
|
"requests are not allowed due to security reasons. Use asynchronous loading with " +
|
"Ext.require instead.", synchronous);
|
//</debug>
|
}
|
else if ((status >= 200 && status < 300) || (status === 304)
|
//<if isNonBrowser>
|
|| isPhantomJS
|
//</if>
|
) {
|
// Debugger friendly, file names are still shown even though they're eval'ed code
|
// Breakpoints work on both Firebug and Chrome's Web Inspector
|
if (!Ext.isIE) {
|
debugSourceURL = "\n//@ sourceURL=" + url;
|
}
|
|
Ext.globalEval(xhr.responseText + debugSourceURL);
|
|
onLoad.call(scope);
|
}
|
else {
|
//<debug>
|
onError.call(Loader, "Failed loading synchronously via XHR: '" + url + "'; please " +
|
"verify that the file exists. " +
|
"XHR status code: " + status, synchronous);
|
//</debug>
|
}
|
|
// Prevent potential IE memory leak
|
xhr = null;
|
}
|
},
|
|
// documented above
|
syncRequire: function() {
|
var syncModeEnabled = Loader.syncModeEnabled;
|
|
if (!syncModeEnabled) {
|
Loader.syncModeEnabled = true;
|
}
|
|
Loader.require.apply(Loader, arguments);
|
|
if (!syncModeEnabled) {
|
Loader.syncModeEnabled = false;
|
}
|
|
Loader.refreshQueue();
|
},
|
|
// documented above
|
require: function(expressions, fn, scope, excludes) {
|
var excluded = {},
|
included = {},
|
excludedClassNames = [],
|
possibleClassNames = [],
|
classNames = [],
|
references = [],
|
callback,
|
syncModeEnabled,
|
filePath, expression, exclude, className,
|
possibleClassName, i, j, ln, subLn;
|
|
if (excludes) {
|
// Convert possible single string to an array.
|
excludes = (typeof excludes === 'string') ? [ excludes ] : excludes;
|
|
for (i = 0,ln = excludes.length; i < ln; i++) {
|
exclude = excludes[i];
|
|
if (typeof exclude == 'string' && exclude.length > 0) {
|
excludedClassNames = Manager.getNamesByExpression(exclude);
|
|
for (j = 0,subLn = excludedClassNames.length; j < subLn; j++) {
|
excluded[excludedClassNames[j]] = true;
|
}
|
}
|
}
|
}
|
|
// Convert possible single string to an array.
|
expressions = (typeof expressions === 'string') ? [ expressions ] : (expressions ? expressions : []);
|
|
if (fn) {
|
if (fn.length > 0) {
|
callback = function() {
|
var classes = [],
|
i, ln;
|
|
for (i = 0,ln = references.length; i < ln; i++) {
|
classes.push(Manager.get(references[i]));
|
}
|
|
return fn.apply(this, classes);
|
};
|
}
|
else {
|
callback = fn;
|
}
|
}
|
else {
|
callback = Ext.emptyFn;
|
}
|
|
scope = scope || Ext.global;
|
|
for (i = 0,ln = expressions.length; i < ln; i++) {
|
expression = expressions[i];
|
|
if (typeof expression == 'string' && expression.length > 0) {
|
possibleClassNames = Manager.getNamesByExpression(expression);
|
subLn = possibleClassNames.length;
|
|
for (j = 0; j < subLn; j++) {
|
possibleClassName = possibleClassNames[j];
|
|
if (excluded[possibleClassName] !== true) {
|
references.push(possibleClassName);
|
|
if (!Manager.isCreated(possibleClassName) && !included[possibleClassName]) {
|
included[possibleClassName] = true;
|
classNames.push(possibleClassName);
|
}
|
}
|
}
|
}
|
}
|
|
// If the dynamic dependency feature is not being used, throw an error
|
// if the dependencies are not defined
|
if (classNames.length > 0) {
|
if (!Loader.config.enabled) {
|
throw new Error("Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +
|
"Missing required class" + ((classNames.length > 1) ? "es" : "") + ": " + classNames.join(', '));
|
}
|
}
|
else {
|
callback.call(scope);
|
return Loader;
|
}
|
|
syncModeEnabled = Loader.syncModeEnabled;
|
|
if (!syncModeEnabled) {
|
queue.push({
|
requires: classNames.slice(), // this array will be modified as the queue is processed,
|
// so we need a copy of it
|
callback: callback,
|
scope: scope
|
});
|
}
|
|
ln = classNames.length;
|
|
for (i = 0; i < ln; i++) {
|
className = classNames[i];
|
|
filePath = Loader.getPath(className);
|
|
// If we are synchronously loading a file that has already been asychronously loaded before
|
// we need to destroy the script tag and revert the count
|
// This file will then be forced loaded in synchronous
|
if (syncModeEnabled && isClassFileLoaded.hasOwnProperty(className)) {
|
if (!isClassFileLoaded[className]) {
|
Loader.numPendingFiles--;
|
Loader.removeScriptElement(filePath);
|
delete isClassFileLoaded[className];
|
}
|
}
|
|
if (!isClassFileLoaded.hasOwnProperty(className)) {
|
isClassFileLoaded[className] = false;
|
classNameToFilePathMap[className] = filePath;
|
|
Loader.numPendingFiles++;
|
Loader.loadScriptFile(
|
filePath,
|
pass(Loader.onFileLoaded, [className, filePath], Loader),
|
pass(Loader.onFileLoadError, [className, filePath], Loader),
|
Loader,
|
syncModeEnabled
|
);
|
}
|
}
|
|
if (syncModeEnabled) {
|
callback.call(scope);
|
|
if (ln === 1) {
|
return Manager.get(className);
|
}
|
}
|
|
return Loader;
|
},
|
|
<span id='Ext-Loader-method-onFileLoaded'> /**
|
</span> * @private
|
* @param {String} className
|
* @param {String} filePath
|
*/
|
onFileLoaded: function(className, filePath) {
|
var loaded = isClassFileLoaded[className];
|
Loader.numLoadedFiles++;
|
|
isClassFileLoaded[className] = true;
|
isFileLoaded[filePath] = true;
|
|
// In FF, when we sync load something that has had a script tag inserted, the load event may
|
// sometimes fire even if we clean it up and set it to null, so check if we're already loaded here.
|
if (!loaded) {
|
Loader.numPendingFiles--;
|
}
|
|
if (Loader.numPendingFiles === 0) {
|
Loader.refreshQueue();
|
}
|
|
//<debug>
|
if (!Loader.syncModeEnabled && Loader.numPendingFiles === 0 && Loader.isLoading && !Loader.hasFileLoadError) {
|
var missingClasses = [],
|
missingPaths = [],
|
requires,
|
i, ln, j, subLn;
|
|
for (i = 0,ln = queue.length; i < ln; i++) {
|
requires = queue[i].requires;
|
|
for (j = 0,subLn = requires.length; j < subLn; j++) {
|
if (isClassFileLoaded[requires[j]]) {
|
missingClasses.push(requires[j]);
|
}
|
}
|
}
|
|
if (missingClasses.length < 1) {
|
return;
|
}
|
|
missingClasses = Ext.Array.filter(Ext.Array.unique(missingClasses), function(item) {
|
return !requiresMap.hasOwnProperty(item);
|
}, Loader);
|
|
if (missingClasses.length < 1) {
|
return;
|
}
|
|
for (i = 0,ln = missingClasses.length; i < ln; i++) {
|
missingPaths.push(classNameToFilePathMap[missingClasses[i]]);
|
}
|
|
throw new Error("The following classes are not declared even if their files have been " +
|
"loaded: '" + missingClasses.join("', '") + "'. Please check the source code of their " +
|
"corresponding files for possible typos: '" + missingPaths.join("', '"));
|
}
|
//</debug>
|
},
|
|
<span id='Ext-Loader-method-onFileLoadError'> /**
|
</span> * @private
|
*/
|
onFileLoadError: function(className, filePath, errorMessage, isSynchronous) {
|
Loader.numPendingFiles--;
|
Loader.hasFileLoadError = true;
|
|
//<debug error>
|
throw new Error("[Ext.Loader] " + errorMessage);
|
//</debug>
|
},
|
|
<span id='Ext-Loader-method-addUsedClasses'> /**
|
</span> * @private
|
* Ensure that any classes referenced in the `uses` property are loaded.
|
*/
|
addUsedClasses: function (classes) {
|
var cls, i, ln;
|
|
if (classes) {
|
classes = (typeof classes == 'string') ? [classes] : classes;
|
for (i = 0, ln = classes.length; i < ln; i++) {
|
cls = classes[i];
|
if (typeof cls == 'string' && !Ext.Array.contains(usedClasses, cls)) {
|
usedClasses.push(cls);
|
}
|
}
|
}
|
|
return Loader;
|
},
|
|
<span id='Ext-Loader-method-triggerReady'> /**
|
</span> * @private
|
*/
|
triggerReady: function() {
|
var listener,
|
refClasses = usedClasses;
|
|
if (Loader.isLoading) {
|
Loader.isLoading = false;
|
|
if (refClasses.length !== 0) {
|
// Clone then empty the array to eliminate potential recursive loop issue
|
refClasses = refClasses.slice();
|
usedClasses.length = 0;
|
// this may immediately call us back if all 'uses' classes
|
// have been loaded
|
Loader.require(refClasses, Loader.triggerReady, Loader);
|
return Loader;
|
}
|
}
|
|
Ext.Array.sort(readyListeners, comparePriority);
|
|
// this method can be called with Loader.isLoading either true or false
|
// (can be called with false when all 'uses' classes are already loaded)
|
// this may bypass the above if condition
|
while (readyListeners.length && !Loader.isLoading) {
|
// calls to refreshQueue may re-enter triggerReady
|
// so we cannot necessarily iterate the readyListeners array
|
listener = readyListeners.shift();
|
listener.fn.call(listener.scope);
|
}
|
|
return Loader;
|
},
|
|
// Documented above already
|
onReady: function(fn, scope, withDomReady, options) {
|
var oldFn;
|
|
if (withDomReady !== false && Ext.onDocumentReady) {
|
oldFn = fn;
|
|
fn = function() {
|
Ext.onDocumentReady(oldFn, scope, options);
|
};
|
}
|
|
if (!Loader.isLoading) {
|
fn.call(scope);
|
}
|
else {
|
readyListeners.push({
|
fn: fn,
|
scope: scope,
|
priority: (options && options.priority) || 0
|
});
|
}
|
},
|
|
<span id='Ext-Loader-method-historyPush'> /**
|
</span> * @private
|
* @param {String} className
|
*/
|
historyPush: function(className) {
|
if (className && isClassFileLoaded.hasOwnProperty(className) && !isInHistory[className]) {
|
isInHistory[className] = true;
|
history.push(className);
|
}
|
return Loader;
|
}
|
});
|
|
<span id='Ext-Loader-method-disableCacheBuster'> /**
|
</span> * Turns on or off the "cache buster" applied to dynamically loaded scripts. Normally
|
* dynamically loaded scripts have an extra query parameter appended to avoid stale
|
* cached scripts. This method can be used to disable this mechanism, and is primarily
|
* useful for testing. This is done using a cookie.
|
* @param {Boolean} disable True to disable the cache buster.
|
* @param {String} [path="/"] An optional path to scope the cookie.
|
* @private
|
*/
|
Ext.disableCacheBuster = function (disable, path) {
|
var date = new Date();
|
date.setTime(date.getTime() + (disable ? 10*365 : -1) * 24*60*60*1000);
|
date = date.toGMTString();
|
document.cookie = 'ext-cache=1; expires=' + date + '; path='+(path || '/');
|
};
|
|
//<if nonBrowser>
|
if (isNonBrowser) {
|
if (isNodeJS) {
|
Ext.apply(Loader, {
|
syncModeEnabled: true,
|
setPath: flexSetter(function(name, path) {
|
path = require('fs').realpathSync(path);
|
Loader.config.paths[name] = path;
|
|
return Loader;
|
}),
|
|
loadScriptFile: function(filePath, onLoad, onError, scope, synchronous) {
|
require(filePath);
|
onLoad.call(scope);
|
}
|
});
|
}
|
else if (isJsdb) {
|
Ext.apply(Loader, {
|
syncModeEnabled: true,
|
loadScriptFile: function(filePath, onLoad, onError, scope, synchronous) {
|
load(filePath);
|
onLoad.call(scope);
|
}
|
});
|
}
|
}
|
//</if>
|
//</feature>
|
|
<span id='Ext-method-require'> /**
|
</span> * @member Ext
|
* @method require
|
* @inheritdoc Ext.Loader#require
|
*/
|
Ext.require = alias(Loader, 'require');
|
|
<span id='Ext-method-syncRequire'> /**
|
</span> * @member Ext
|
* @method syncRequire
|
* @inheritdoc Ext.Loader#syncRequire
|
*/
|
Ext.syncRequire = alias(Loader, 'syncRequire');
|
|
<span id='Ext-method-exclude'> /**
|
</span> * Convenient shortcut to {@link Ext.Loader#exclude}
|
* @member Ext
|
* @method exclude
|
* @inheritdoc Ext.Loader#exclude
|
*/
|
Ext.exclude = alias(Loader, 'exclude');
|
|
<span id='Ext-method-onReady'> /**
|
</span> * @member Ext
|
* @method onReady
|
* @ignore
|
*/
|
Ext.onReady = function(fn, scope, options) {
|
Loader.onReady(fn, scope, true, options);
|
};
|
|
<span id='Ext-Class-cfg-requires'> /**
|
</span> * @cfg {String[]} requires
|
* @member Ext.Class
|
* List of classes that have to be loaded before instantiating this class.
|
* For example:
|
*
|
* Ext.define('Mother', {
|
* requires: ['Child'],
|
* giveBirth: function() {
|
* // we can be sure that child class is available.
|
* return new Child();
|
* }
|
* });
|
*/
|
Class.registerPreprocessor('loader', function(cls, data, hooks, continueFn) {
|
//<debug>
|
Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.Loader#loaderPreprocessor', arguments);
|
//</debug>
|
|
var me = this,
|
dependencies = [],
|
dependency,
|
className = Manager.getName(cls),
|
i, j, ln, subLn, value, propertyName, propertyValue,
|
requiredMap, requiredDep;
|
|
/*
|
Loop through the dependencyProperties, look for string class names and push
|
them into a stack, regardless of whether the property's value is a string, array or object. For example:
|
{
|
extend: 'Ext.MyClass',
|
requires: ['Ext.some.OtherClass'],
|
mixins: {
|
observable: 'Ext.util.Observable';
|
}
|
}
|
which will later be transformed into:
|
{
|
extend: Ext.MyClass,
|
requires: [Ext.some.OtherClass],
|
mixins: {
|
observable: Ext.util.Observable;
|
}
|
}
|
*/
|
|
for (i = 0,ln = dependencyProperties.length; i < ln; i++) {
|
propertyName = dependencyProperties[i];
|
|
if (data.hasOwnProperty(propertyName)) {
|
propertyValue = data[propertyName];
|
|
if (typeof propertyValue == 'string') {
|
dependencies.push(propertyValue);
|
}
|
else if (propertyValue instanceof Array) {
|
for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
|
value = propertyValue[j];
|
|
if (typeof value == 'string') {
|
dependencies.push(value);
|
}
|
}
|
}
|
else if (typeof propertyValue != 'function') {
|
for (j in propertyValue) {
|
if (propertyValue.hasOwnProperty(j)) {
|
value = propertyValue[j];
|
|
if (typeof value == 'string') {
|
dependencies.push(value);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
if (dependencies.length === 0) {
|
return;
|
}
|
|
//<feature classSystem.loader>
|
//<debug error>
|
var deadlockPath = [],
|
detectDeadlock;
|
|
/*
|
Automatically detect deadlocks before-hand,
|
will throw an error with detailed path for ease of debugging. Examples of deadlock cases:
|
|
- A extends B, then B extends A
|
- A requires B, B requires C, then C requires A
|
|
The detectDeadlock function will recursively transverse till the leaf, hence it can detect deadlocks
|
no matter how deep the path is.
|
*/
|
|
if (className) {
|
requiresMap[className] = dependencies;
|
//<debug>
|
requiredMap = Loader.requiredByMap || (Loader.requiredByMap = {});
|
|
for (i = 0,ln = dependencies.length; i < ln; i++) {
|
dependency = dependencies[i];
|
(requiredMap[dependency] || (requiredMap[dependency] = [])).push(className);
|
}
|
//</debug>
|
detectDeadlock = function(cls) {
|
deadlockPath.push(cls);
|
|
if (requiresMap[cls]) {
|
if (Ext.Array.contains(requiresMap[cls], className)) {
|
throw new Error("Deadlock detected while loading dependencies! '" + className + "' and '" +
|
deadlockPath[1] + "' " + "mutually require each other. Path: " +
|
deadlockPath.join(' -> ') + " -> " + deadlockPath[0]);
|
}
|
|
for (i = 0,ln = requiresMap[cls].length; i < ln; i++) {
|
detectDeadlock(requiresMap[cls][i]);
|
}
|
}
|
};
|
|
detectDeadlock(className);
|
}
|
|
//</debug>
|
//</feature>
|
|
Loader.require(dependencies, function() {
|
for (i = 0,ln = dependencyProperties.length; i < ln; i++) {
|
propertyName = dependencyProperties[i];
|
|
if (data.hasOwnProperty(propertyName)) {
|
propertyValue = data[propertyName];
|
|
if (typeof propertyValue == 'string') {
|
data[propertyName] = Manager.get(propertyValue);
|
}
|
else if (propertyValue instanceof Array) {
|
for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
|
value = propertyValue[j];
|
|
if (typeof value == 'string') {
|
data[propertyName][j] = Manager.get(value);
|
}
|
}
|
}
|
else if (typeof propertyValue != 'function') {
|
for (var k in propertyValue) {
|
if (propertyValue.hasOwnProperty(k)) {
|
value = propertyValue[k];
|
|
if (typeof value == 'string') {
|
data[propertyName][k] = Manager.get(value);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
continueFn.call(me, cls, data, hooks);
|
});
|
|
return false;
|
}, true, 'after', 'className');
|
|
//<feature classSystem.loader>
|
<span id='Ext-Class-cfg-uses'> /**
|
</span> * @cfg {String[]} uses
|
* @member Ext.Class
|
* List of optional classes to load together with this class. These aren't neccessarily loaded before
|
* this class is created, but are guaranteed to be available before Ext.onReady listeners are
|
* invoked. For example:
|
*
|
* Ext.define('Mother', {
|
* uses: ['Child'],
|
* giveBirth: function() {
|
* // This code might, or might not work:
|
* // return new Child();
|
*
|
* // Instead use Ext.create() to load the class at the spot if not loaded already:
|
* return Ext.create('Child');
|
* }
|
* });
|
*/
|
Manager.registerPostprocessor('uses', function(name, cls, data) {
|
//<debug>
|
Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.Loader#usesPostprocessor', arguments);
|
//</debug>
|
|
var uses = data.uses;
|
if (uses) {
|
Loader.addUsedClasses(uses);
|
}
|
});
|
|
Manager.onCreated(Loader.historyPush);
|
//</feature>
|
};
|
|
// simple mechanism for automated means of injecting large amounts of dependency info
|
// at the appropriate time in the load cycle
|
if (Ext._classPathMetadata) {
|
Ext.Loader.addClassPathMappings(Ext._classPathMetadata);
|
Ext._classPathMetadata = null;
|
}
|
|
// initalize the default path of the framework
|
(function() {
|
var scripts = document.getElementsByTagName('script'),
|
currentScript = scripts[scripts.length - 1],
|
src = currentScript.src,
|
path = src.substring(0, src.lastIndexOf('/') + 1),
|
Loader = Ext.Loader;
|
|
//<debug>
|
if(src.indexOf("/platform/core/src/class/") != -1) {
|
path = path + "../../../../extjs/";
|
} else if(src.indexOf("/core/src/class/") != -1) {
|
path = path + "../../../";
|
}
|
//</debug>
|
|
Loader.setConfig({
|
enabled: true,
|
disableCaching:
|
//<debug>
|
(/[?&](?:cache|disableCacheBuster)\b/i.test(location.search) ||
|
/(^|[ ;])ext-cache=1/.test(document.cookie)) ? false :
|
//</debug>
|
true,
|
paths: {
|
'Ext': path + 'src'
|
}
|
});
|
})();
|
|
// allows a tools like dynatrace to deterministically detect onReady state by invoking
|
// a callback (intended for external consumption)
|
Ext._endTime = new Date().getTime();
|
if (Ext._beforereadyhandler){
|
Ext._beforereadyhandler();
|
}
|
</pre>
|
</body>
|
</html>
|