##// END OF EJS Templates
Tests rewrite for 1.2 added some globals configs to make tests easier....
Tests rewrite for 1.2 added some globals configs to make tests easier. Fixed search index_location to take from configuration files now fixed git http_user_agent bug

File last commit:

r547:1e757ac9 default
r688:8acbfa83 beta
Show More
yuiloader.js
3879 lines | 122.5 KiB | application/javascript | JavascriptLexer
/*
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.8.0r4
*/
/**
* The YAHOO object is the single global object used by YUI Library. It
* contains utility function for setting up namespaces, inheritance, and
* logging. YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces
* created automatically for and used by the library.
* @module yahoo
* @title YAHOO Global
*/
/**
* YAHOO_config is not included as part of the library. Instead it is an
* object that can be defined by the implementer immediately before
* including the YUI library. The properties included in this object
* will be used to configure global properties needed as soon as the
* library begins to load.
* @class YAHOO_config
* @static
*/
/**
* A reference to a function that will be executed every time a YAHOO module
* is loaded. As parameter, this function will receive the version
* information for the module. See <a href="YAHOO.env.html#getVersion">
* YAHOO.env.getVersion</a> for the description of the version data structure.
* @property listener
* @type Function
* @static
* @default undefined
*/
/**
* Set to true if the library will be dynamically loaded after window.onload.
* Defaults to false
* @property injecting
* @type boolean
* @static
* @default undefined
*/
/**
* Instructs the yuiloader component to dynamically load yui components and
* their dependencies. See the yuiloader documentation for more information
* about dynamic loading
* @property load
* @static
* @default undefined
* @see yuiloader
*/
/**
* Forces the use of the supplied locale where applicable in the library
* @property locale
* @type string
* @static
* @default undefined
*/
if (typeof YAHOO == "undefined" || !YAHOO) {
/**
* The YAHOO global namespace object. If YAHOO is already defined, the
* existing YAHOO object will not be overwritten so that defined
* namespaces are preserved.
* @class YAHOO
* @static
*/
var YAHOO = {};
}
/**
* Returns the namespace specified and creates it if it doesn't exist
* <pre>
* YAHOO.namespace("property.package");
* YAHOO.namespace("YAHOO.property.package");
* </pre>
* Either of the above would create YAHOO.property, then
* YAHOO.property.package
*
* Be careful when naming packages. Reserved words may work in some browsers
* and not others. For instance, the following will fail in Safari:
* <pre>
* YAHOO.namespace("really.long.nested.namespace");
* </pre>
* This fails because "long" is a future reserved word in ECMAScript
*
* For implementation code that uses YUI, do not create your components
* in the namespaces defined by YUI (
* <code>YAHOO.util</code>,
* <code>YAHOO.widget</code>,
* <code>YAHOO.lang</code>,
* <code>YAHOO.tool</code>,
* <code>YAHOO.example</code>,
* <code>YAHOO.env</code>) -- create your own namespace (e.g., 'companyname').
*
* @method namespace
* @static
* @param {String*} arguments 1-n namespaces to create
* @return {Object} A reference to the last namespace object created
*/
YAHOO.namespace = function() {
var a=arguments, o=null, i, j, d;
for (i=0; i<a.length; i=i+1) {
d=(""+a[i]).split(".");
o=YAHOO;
// YAHOO is implied, so it is ignored if it is included
for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) {
o[d[j]]=o[d[j]] || {};
o=o[d[j]];
}
}
return o;
};
/**
* Uses YAHOO.widget.Logger to output a log message, if the widget is
* available.
*
* @method log
* @static
* @param {String} msg The message to log.
* @param {String} cat The log category for the message. Default
* categories are "info", "warn", "error", time".
* Custom categories can be used as well. (opt)
* @param {String} src The source of the the message (opt)
* @return {Boolean} True if the log operation was successful.
*/
YAHOO.log = function(msg, cat, src) {
var l=YAHOO.widget.Logger;
if(l && l.log) {
return l.log(msg, cat, src);
} else {
return false;
}
};
/**
* Registers a module with the YAHOO object
* @method register
* @static
* @param {String} name the name of the module (event, slider, etc)
* @param {Function} mainClass a reference to class in the module. This
* class will be tagged with the version info
* so that it will be possible to identify the
* version that is in use when multiple versions
* have loaded
* @param {Object} data metadata object for the module. Currently it
* is expected to contain a "version" property
* and a "build" property at minimum.
*/
YAHOO.register = function(name, mainClass, data) {
var mods = YAHOO.env.modules, m, v, b, ls, i;
if (!mods[name]) {
mods[name] = {
versions:[],
builds:[]
};
}
m = mods[name];
v = data.version;
b = data.build;
ls = YAHOO.env.listeners;
m.name = name;
m.version = v;
m.build = b;
m.versions.push(v);
m.builds.push(b);
m.mainClass = mainClass;
// fire the module load listeners
for (i=0;i<ls.length;i=i+1) {
ls[i](m);
}
// label the main class
if (mainClass) {
mainClass.VERSION = v;
mainClass.BUILD = b;
} else {
YAHOO.log("mainClass is undefined for module " + name, "warn");
}
};
/**
* YAHOO.env is used to keep track of what is known about the YUI library and
* the browsing environment
* @class YAHOO.env
* @static
*/
YAHOO.env = YAHOO.env || {
/**
* Keeps the version info for all YUI modules that have reported themselves
* @property modules
* @type Object[]
*/
modules: [],
/**
* List of functions that should be executed every time a YUI module
* reports itself.
* @property listeners
* @type Function[]
*/
listeners: []
};
/**
* Returns the version data for the specified module:
* <dl>
* <dt>name:</dt> <dd>The name of the module</dd>
* <dt>version:</dt> <dd>The version in use</dd>
* <dt>build:</dt> <dd>The build number in use</dd>
* <dt>versions:</dt> <dd>All versions that were registered</dd>
* <dt>builds:</dt> <dd>All builds that were registered.</dd>
* <dt>mainClass:</dt> <dd>An object that was was stamped with the
* current version and build. If
* mainClass.VERSION != version or mainClass.BUILD != build,
* multiple versions of pieces of the library have been
* loaded, potentially causing issues.</dd>
* </dl>
*
* @method getVersion
* @static
* @param {String} name the name of the module (event, slider, etc)
* @return {Object} The version info
*/
YAHOO.env.getVersion = function(name) {
return YAHOO.env.modules[name] || null;
};
/**
* Do not fork for a browser if it can be avoided. Use feature detection when
* you can. Use the user agent as a last resort. YAHOO.env.ua stores a version
* number for the browser engine, 0 otherwise. This value may or may not map
* to the version number of the browser using the engine. The value is
* presented as a float so that it can easily be used for boolean evaluation
* as well as for looking for a particular range of versions. Because of this,
* some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9
* reports 1.8).
* @class YAHOO.env.ua
* @static
*/
YAHOO.env.ua = function() {
var numberfy = function(s) {
var c = 0;
return parseFloat(s.replace(/\./g, function() {
return (c++ == 1) ? '' : '.';
}));
},
nav = navigator,
o = {
/**
* Internet Explorer version number or 0. Example: 6
* @property ie
* @type float
*/
ie: 0,
/**
* Opera version number or 0. Example: 9.2
* @property opera
* @type float
*/
opera: 0,
/**
* Gecko engine revision number. Will evaluate to 1 if Gecko
* is detected but the revision could not be found. Other browsers
* will be 0. Example: 1.8
* <pre>
* Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7
* Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
* Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
* Firefox 3 alpha: 1.9a4 <-- Reports 1.9
* </pre>
* @property gecko
* @type float
*/
gecko: 0,
/**
* AppleWebKit version. KHTML browsers that are not WebKit browsers
* will evaluate to 1, other browsers 0. Example: 418.9.1
* <pre>
* Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
* latest available for Mac OSX 10.3.
* Safari 2.0.2: 416 <-- hasOwnProperty introduced
* Safari 2.0.4: 418 <-- preventDefault fixed
* Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
* different versions of webkit
* Safari 2.0.4 (419.3): 419 <-- Tiger installations that have been
* updated, but not updated
* to the latest patch.
* Webkit 212 nightly: 522+ <-- Safari 3.0 precursor (with native SVG
* and many major issues fixed).
* 3.x yahoo.com, flickr:422 <-- Safari 3.x hacks the user agent
* string when hitting yahoo.com and
* flickr.com.
* Safari 3.0.4 (523.12):523.12 <-- First Tiger release - automatic update
* from 2.x via the 10.4.11 OS patch
* Webkit nightly 1/2008:525+ <-- Supports DOMContentLoaded event.
* yahoo.com user agent hack removed.
*
* </pre>
* http://developer.apple.com/internet/safari/uamatrix.html
* @property webkit
* @type float
*/
webkit: 0,
/**
* The mobile property will be set to a string containing any relevant
* user agent information when a modern mobile browser is detected.
* Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
* devices with the WebKit-based browser, and Opera Mini.
* @property mobile
* @type string
*/
mobile: null,
/**
* Adobe AIR version number or 0. Only populated if webkit is detected.
* Example: 1.0
* @property air
* @type float
*/
air: 0,
/**
* Google Caja version number or 0.
* @property caja
* @type float
*/
caja: nav.cajaVersion,
/**
* Set to true if the page appears to be in SSL
* @property secure
* @type boolean
* @static
*/
secure: false,
/**
* The operating system. Currently only detecting windows or macintosh
* @property os
* @type string
* @static
*/
os: null
},
ua = navigator && navigator.userAgent,
loc = window && window.location,
href = loc && loc.href,
m;
o.secure = href && (href.toLowerCase().indexOf("https") === 0);
if (ua) {
if ((/windows|win32/i).test(ua)) {
o.os = 'windows';
} else if ((/macintosh/i).test(ua)) {
o.os = 'macintosh';
}
// Modern KHTML browsers should qualify as Safari X-Grade
if ((/KHTML/).test(ua)) {
o.webkit=1;
}
// Modern WebKit browsers are at least X-Grade
m=ua.match(/AppleWebKit\/([^\s]*)/);
if (m&&m[1]) {
o.webkit=numberfy(m[1]);
// Mobile browser check
if (/ Mobile\//.test(ua)) {
o.mobile = "Apple"; // iPhone or iPod Touch
} else {
m=ua.match(/NokiaN[^\/]*/);
if (m) {
o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
}
}
m=ua.match(/AdobeAIR\/([^\s]*)/);
if (m) {
o.air = m[0]; // Adobe AIR 1.0 or better
}
}
if (!o.webkit) { // not webkit
// @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
m=ua.match(/Opera[\s\/]([^\s]*)/);
if (m&&m[1]) {
o.opera=numberfy(m[1]);
m=ua.match(/Opera Mini[^;]*/);
if (m) {
o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
}
} else { // not opera or webkit
m=ua.match(/MSIE\s([^;]*)/);
if (m&&m[1]) {
o.ie=numberfy(m[1]);
} else { // not opera, webkit, or ie
m=ua.match(/Gecko\/([^\s]*)/);
if (m) {
o.gecko=1; // Gecko detected, look for revision
m=ua.match(/rv:([^\s\)]*)/);
if (m&&m[1]) {
o.gecko=numberfy(m[1]);
}
}
}
}
}
}
return o;
}();
/*
* Initializes the global by creating the default namespaces and applying
* any new configuration information that is detected. This is the setup
* for env.
* @method init
* @static
* @private
*/
(function() {
YAHOO.namespace("util", "widget", "example");
/*global YAHOO_config*/
if ("undefined" !== typeof YAHOO_config) {
var l=YAHOO_config.listener, ls=YAHOO.env.listeners,unique=true, i;
if (l) {
// if YAHOO is loaded multiple times we need to check to see if
// this is a new config object. If it is, add the new component
// load listener to the stack
for (i=0; i<ls.length; i++) {
if (ls[i] == l) {
unique = false;
break;
}
}
if (unique) {
ls.push(l);
}
}
}
})();
/**
* Provides the language utilites and extensions used by the library
* @class YAHOO.lang
*/
YAHOO.lang = YAHOO.lang || {};
(function() {
var L = YAHOO.lang,
OP = Object.prototype,
ARRAY_TOSTRING = '[object Array]',
FUNCTION_TOSTRING = '[object Function]',
OBJECT_TOSTRING = '[object Object]',
NOTHING = [],
// ADD = ["toString", "valueOf", "hasOwnProperty"],
ADD = ["toString", "valueOf"],
OB = {
/**
* Determines wheather or not the provided object is an array.
* @method isArray
* @param {any} o The object being testing
* @return {boolean} the result
*/
isArray: function(o) {
return OP.toString.apply(o) === ARRAY_TOSTRING;
},
/**
* Determines whether or not the provided object is a boolean
* @method isBoolean
* @param {any} o The object being testing
* @return {boolean} the result
*/
isBoolean: function(o) {
return typeof o === 'boolean';
},
/**
* Determines whether or not the provided object is a function.
* Note: Internet Explorer thinks certain functions are objects:
*
* var obj = document.createElement("object");
* YAHOO.lang.isFunction(obj.getAttribute) // reports false in IE
*
* var input = document.createElement("input"); // append to body
* YAHOO.lang.isFunction(input.focus) // reports false in IE
*
* You will have to implement additional tests if these functions
* matter to you.
*
* @method isFunction
* @param {any} o The object being testing
* @return {boolean} the result
*/
isFunction: function(o) {
return (typeof o === 'function') || OP.toString.apply(o) === FUNCTION_TOSTRING;
},
/**
* Determines whether or not the provided object is null
* @method isNull
* @param {any} o The object being testing
* @return {boolean} the result
*/
isNull: function(o) {
return o === null;
},
/**
* Determines whether or not the provided object is a legal number
* @method isNumber
* @param {any} o The object being testing
* @return {boolean} the result
*/
isNumber: function(o) {
return typeof o === 'number' && isFinite(o);
},
/**
* Determines whether or not the provided object is of type object
* or function
* @method isObject
* @param {any} o The object being testing
* @return {boolean} the result
*/
isObject: function(o) {
return (o && (typeof o === 'object' || L.isFunction(o))) || false;
},
/**
* Determines whether or not the provided object is a string
* @method isString
* @param {any} o The object being testing
* @return {boolean} the result
*/
isString: function(o) {
return typeof o === 'string';
},
/**
* Determines whether or not the provided object is undefined
* @method isUndefined
* @param {any} o The object being testing
* @return {boolean} the result
*/
isUndefined: function(o) {
return typeof o === 'undefined';
},
/**
* IE will not enumerate native functions in a derived object even if the
* function was overridden. This is a workaround for specific functions
* we care about on the Object prototype.
* @property _IEEnumFix
* @param {Function} r the object to receive the augmentation
* @param {Function} s the object that supplies the properties to augment
* @static
* @private
*/
_IEEnumFix: (YAHOO.env.ua.ie) ? function(r, s) {
var i, fname, f;
for (i=0;i<ADD.length;i=i+1) {
fname = ADD[i];
f = s[fname];
if (L.isFunction(f) && f!=OP[fname]) {
r[fname]=f;
}
}
} : function(){},
/**
* Utility to set up the prototype, constructor and superclass properties to
* support an inheritance strategy that can chain constructors and methods.
* Static members will not be inherited.
*
* @method extend
* @static
* @param {Function} subc the object to modify
* @param {Function} superc the object to inherit
* @param {Object} overrides additional properties/methods to add to the
* subclass prototype. These will override the
* matching items obtained from the superclass
* if present.
*/
extend: function(subc, superc, overrides) {
if (!superc||!subc) {
throw new Error("extend failed, please check that " +
"all dependencies are included.");
}
var F = function() {}, i;
F.prototype=superc.prototype;
subc.prototype=new F();
subc.prototype.constructor=subc;
subc.superclass=superc.prototype;
if (superc.prototype.constructor == OP.constructor) {
superc.prototype.constructor=superc;
}
if (overrides) {
for (i in overrides) {
if (L.hasOwnProperty(overrides, i)) {
subc.prototype[i]=overrides[i];
}
}
L._IEEnumFix(subc.prototype, overrides);
}
},
/**
* Applies all properties in the supplier to the receiver if the
* receiver does not have these properties yet. Optionally, one or
* more methods/properties can be specified (as additional
* parameters). This option will overwrite the property if receiver
* has it already. If true is passed as the third parameter, all
* properties will be applied and _will_ overwrite properties in
* the receiver.
*
* @method augmentObject
* @static
* @since 2.3.0
* @param {Function} r the object to receive the augmentation
* @param {Function} s the object that supplies the properties to augment
* @param {String*|boolean} arguments zero or more properties methods
* to augment the receiver with. If none specified, everything
* in the supplier will be used unless it would
* overwrite an existing property in the receiver. If true
* is specified as the third parameter, all properties will
* be applied and will overwrite an existing property in
* the receiver
*/
augmentObject: function(r, s) {
if (!s||!r) {
throw new Error("Absorb failed, verify dependencies.");
}
var a=arguments, i, p, overrideList=a[2];
if (overrideList && overrideList!==true) { // only absorb the specified properties
for (i=2; i<a.length; i=i+1) {
r[a[i]] = s[a[i]];
}
} else { // take everything, overwriting only if the third parameter is true
for (p in s) {
if (overrideList || !(p in r)) {
r[p] = s[p];
}
}
L._IEEnumFix(r, s);
}
},
/**
* Same as YAHOO.lang.augmentObject, except it only applies prototype properties
* @see YAHOO.lang.augmentObject
* @method augmentProto
* @static
* @param {Function} r the object to receive the augmentation
* @param {Function} s the object that supplies the properties to augment
* @param {String*|boolean} arguments zero or more properties methods
* to augment the receiver with. If none specified, everything
* in the supplier will be used unless it would overwrite an existing
* property in the receiver. if true is specified as the third
* parameter, all properties will be applied and will overwrite an
* existing property in the receiver
*/
augmentProto: function(r, s) {
if (!s||!r) {
throw new Error("Augment failed, verify dependencies.");
}
//var a=[].concat(arguments);
var a=[r.prototype,s.prototype], i;
for (i=2;i<arguments.length;i=i+1) {
a.push(arguments[i]);
}
L.augmentObject.apply(this, a);
},
/**
* Returns a simple string representation of the object or array.
* Other types of objects will be returned unprocessed. Arrays
* are expected to be indexed. Use object notation for
* associative arrays.
* @method dump
* @since 2.3.0
* @param o {Object} The object to dump
* @param d {int} How deep to recurse child objects, default 3
* @return {String} the dump result
*/
dump: function(o, d) {
var i,len,s=[],OBJ="{...}",FUN="f(){...}",
COMMA=', ', ARROW=' => ';
// Cast non-objects to string
// Skip dates because the std toString is what we want
// Skip HTMLElement-like objects because trying to dump
// an element will cause an unhandled exception in FF 2.x
if (!L.isObject(o)) {
return o + "";
} else if (o instanceof Date || ("nodeType" in o && "tagName" in o)) {
return o;
} else if (L.isFunction(o)) {
return FUN;
}
// dig into child objects the depth specifed. Default 3
d = (L.isNumber(d)) ? d : 3;
// arrays [1, 2, 3]
if (L.isArray(o)) {
s.push("[");
for (i=0,len=o.length;i<len;i=i+1) {
if (L.isObject(o[i])) {
s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
} else {
s.push(o[i]);
}
s.push(COMMA);
}
if (s.length > 1) {
s.pop();
}
s.push("]");
// objects {k1 => v1, k2 => v2}
} else {
s.push("{");
for (i in o) {
if (L.hasOwnProperty(o, i)) {
s.push(i + ARROW);
if (L.isObject(o[i])) {
s.push((d > 0) ? L.dump(o[i], d-1) : OBJ);
} else {
s.push(o[i]);
}
s.push(COMMA);
}
}
if (s.length > 1) {
s.pop();
}
s.push("}");
}
return s.join("");
},
/**
* Does variable substitution on a string. It scans through the string
* looking for expressions enclosed in { } braces. If an expression
* is found, it is used a key on the object. If there is a space in
* the key, the first word is used for the key and the rest is provided
* to an optional function to be used to programatically determine the
* value (the extra information might be used for this decision). If
* the value for the key in the object, or what is returned from the
* function has a string value, number value, or object value, it is
* substituted for the bracket expression and it repeats. If this
* value is an object, it uses the Object's toString() if this has
* been overridden, otherwise it does a shallow dump of the key/value
* pairs.
* @method substitute
* @since 2.3.0
* @param s {String} The string that will be modified.
* @param o {Object} An object containing the replacement values
* @param f {Function} An optional function that can be used to
* process each match. It receives the key,
* value, and any extra metadata included with
* the key inside of the braces.
* @return {String} the substituted string
*/
substitute: function (s, o, f) {
var i, j, k, key, v, meta, saved=[], token,
DUMP='dump', SPACE=' ', LBRACE='{', RBRACE='}',
dump, objstr;
for (;;) {
i = s.lastIndexOf(LBRACE);
if (i < 0) {
break;
}
j = s.indexOf(RBRACE, i);
if (i + 1 >= j) {
break;
}
//Extract key and meta info
token = s.substring(i + 1, j);
key = token;
meta = null;
k = key.indexOf(SPACE);
if (k > -1) {
meta = key.substring(k + 1);
key = key.substring(0, k);
}
// lookup the value
v = o[key];
// if a substitution function was provided, execute it
if (f) {
v = f(key, v, meta);
}
if (L.isObject(v)) {
if (L.isArray(v)) {
v = L.dump(v, parseInt(meta, 10));
} else {
meta = meta || "";
// look for the keyword 'dump', if found force obj dump
dump = meta.indexOf(DUMP);
if (dump > -1) {
meta = meta.substring(4);
}
objstr = v.toString();
// use the toString if it is not the Object toString
// and the 'dump' meta info was not found
if (objstr === OBJECT_TOSTRING || dump > -1) {
v = L.dump(v, parseInt(meta, 10));
} else {
v = objstr;
}
}
} else if (!L.isString(v) && !L.isNumber(v)) {
// This {block} has no replace string. Save it for later.
v = "~-" + saved.length + "-~";
saved[saved.length] = token;
// break;
}
s = s.substring(0, i) + v + s.substring(j + 1);
}
// restore saved {block}s
for (i=saved.length-1; i>=0; i=i-1) {
s = s.replace(new RegExp("~-" + i + "-~"), "{" + saved[i] + "}", "g");
}
return s;
},
/**
* Returns a string without any leading or trailing whitespace. If
* the input is not a string, the input will be returned untouched.
* @method trim
* @since 2.3.0
* @param s {string} the string to trim
* @return {string} the trimmed string
*/
trim: function(s){
try {
return s.replace(/^\s+|\s+$/g, "");
} catch(e) {
return s;
}
},
/**
* Returns a new object containing all of the properties of
* all the supplied objects. The properties from later objects
* will overwrite those in earlier objects.
* @method merge
* @since 2.3.0
* @param arguments {Object*} the objects to merge
* @return the new merged object
*/
merge: function() {
var o={}, a=arguments, l=a.length, i;
for (i=0; i<l; i=i+1) {
L.augmentObject(o, a[i], true);
}
return o;
},
/**
* Executes the supplied function in the context of the supplied
* object 'when' milliseconds later. Executes the function a
* single time unless periodic is set to true.
* @method later
* @since 2.4.0
* @param when {int} the number of milliseconds to wait until the fn
* is executed
* @param o the context object
* @param fn {Function|String} the function to execute or the name of
* the method in the 'o' object to execute
* @param data [Array] data that is provided to the function. This accepts
* either a single item or an array. If an array is provided, the
* function is executed with one parameter for each array item. If
* you need to pass a single array parameter, it needs to be wrapped in
* an array [myarray]
* @param periodic {boolean} if true, executes continuously at supplied
* interval until canceled
* @return a timer object. Call the cancel() method on this object to
* stop the timer.
*/
later: function(when, o, fn, data, periodic) {
when = when || 0;
o = o || {};
var m=fn, d=data, f, r;
if (L.isString(fn)) {
m = o[fn];
}
if (!m) {
throw new TypeError("method undefined");
}
if (d && !L.isArray(d)) {
d = [data];
}
f = function() {
m.apply(o, d || NOTHING);
};
r = (periodic) ? setInterval(f, when) : setTimeout(f, when);
return {
interval: periodic,
cancel: function() {
if (this.interval) {
clearInterval(r);
} else {
clearTimeout(r);
}
}
};
},
/**
* A convenience method for detecting a legitimate non-null value.
* Returns false for null/undefined/NaN, true for other values,
* including 0/false/''
* @method isValue
* @since 2.3.0
* @param o {any} the item to test
* @return {boolean} true if it is not null/undefined/NaN || false
*/
isValue: function(o) {
// return (o || o === false || o === 0 || o === ''); // Infinity fails
return (L.isObject(o) || L.isString(o) || L.isNumber(o) || L.isBoolean(o));
}
};
/**
* Determines whether or not the property was added
* to the object instance. Returns false if the property is not present
* in the object, or was inherited from the prototype.
* This abstraction is provided to enable hasOwnProperty for Safari 1.3.x.
* There is a discrepancy between YAHOO.lang.hasOwnProperty and
* Object.prototype.hasOwnProperty when the property is a primitive added to
* both the instance AND prototype with the same value:
* <pre>
* var A = function() {};
* A.prototype.foo = 'foo';
* var a = new A();
* a.foo = 'foo';
* alert(a.hasOwnProperty('foo')); // true
* alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback
* </pre>
* @method hasOwnProperty
* @param {any} o The object being testing
* @param prop {string} the name of the property to test
* @return {boolean} the result
*/
L.hasOwnProperty = (OP.hasOwnProperty) ?
function(o, prop) {
return o && o.hasOwnProperty(prop);
} : function(o, prop) {
return !L.isUndefined(o[prop]) &&
o.constructor.prototype[prop] !== o[prop];
};
// new lang wins
OB.augmentObject(L, OB, true);
/*
* An alias for <a href="YAHOO.lang.html">YAHOO.lang</a>
* @class YAHOO.util.Lang
*/
YAHOO.util.Lang = L;
/**
* Same as YAHOO.lang.augmentObject, except it only applies prototype
* properties. This is an alias for augmentProto.
* @see YAHOO.lang.augmentObject
* @method augment
* @static
* @param {Function} r the object to receive the augmentation
* @param {Function} s the object that supplies the properties to augment
* @param {String*|boolean} arguments zero or more properties methods to
* augment the receiver with. If none specified, everything
* in the supplier will be used unless it would
* overwrite an existing property in the receiver. if true
* is specified as the third parameter, all properties will
* be applied and will overwrite an existing property in
* the receiver
*/
L.augment = L.augmentProto;
/**
* An alias for <a href="YAHOO.lang.html#augment">YAHOO.lang.augment</a>
* @for YAHOO
* @method augment
* @static
* @param {Function} r the object to receive the augmentation
* @param {Function} s the object that supplies the properties to augment
* @param {String*} arguments zero or more properties methods to
* augment the receiver with. If none specified, everything
* in the supplier will be used unless it would
* overwrite an existing property in the receiver
*/
YAHOO.augment = L.augmentProto;
/**
* An alias for <a href="YAHOO.lang.html#extend">YAHOO.lang.extend</a>
* @method extend
* @static
* @param {Function} subc the object to modify
* @param {Function} superc the object to inherit
* @param {Object} overrides additional properties/methods to add to the
* subclass prototype. These will override the
* matching items obtained from the superclass if present.
*/
YAHOO.extend = L.extend;
})();
YAHOO.register("yahoo", YAHOO, {version: "2.8.0r4", build: "2449"});
/**
* Provides a mechanism to fetch remote resources and
* insert them into a document
* @module get
* @requires yahoo
*/
/**
* Fetches and inserts one or more script or link nodes into the document
* @namespace YAHOO.util
* @class YAHOO.util.Get
*/
YAHOO.util.Get = function() {
/**
* hash of queues to manage multiple requests
* @property queues
* @private
*/
var queues={},
/**
* queue index used to generate transaction ids
* @property qidx
* @type int
* @private
*/
qidx=0,
/**
* node index used to generate unique node ids
* @property nidx
* @type int
* @private
*/
nidx=0,
// ridx=0,
// sandboxFrame=null,
/**
* interal property used to prevent multiple simultaneous purge
* processes
* @property purging
* @type boolean
* @private
*/
purging=false,
ua=YAHOO.env.ua,
lang=YAHOO.lang;
/**
* Generates an HTML element, this is not appended to a document
* @method _node
* @param type {string} the type of element
* @param attr {string} the attributes
* @param win {Window} optional window to create the element in
* @return {HTMLElement} the generated node
* @private
*/
var _node = function(type, attr, win) {
var w = win || window, d=w.document, n=d.createElement(type);
for (var i in attr) {
if (attr[i] && YAHOO.lang.hasOwnProperty(attr, i)) {
n.setAttribute(i, attr[i]);
}
}
return n;
};
/**
* Generates a link node
* @method _linkNode
* @param url {string} the url for the css file
* @param win {Window} optional window to create the node in
* @return {HTMLElement} the generated node
* @private
*/
var _linkNode = function(url, win, attributes) {
var o = {
id: "yui__dyn_" + (nidx++),
type: "text/css",
rel: "stylesheet",
href: url
};
if (attributes) {
lang.augmentObject(o, attributes);
}
return _node("link", o, win);
};
/**
* Generates a script node
* @method _scriptNode
* @param url {string} the url for the script file
* @param win {Window} optional window to create the node in
* @return {HTMLElement} the generated node
* @private
*/
var _scriptNode = function(url, win, attributes) {
var o = {
id: "yui__dyn_" + (nidx++),
type: "text/javascript",
src: url
};
if (attributes) {
lang.augmentObject(o, attributes);
}
return _node("script", o, win);
};
/**
* Returns the data payload for callback functions
* @method _returnData
* @private
*/
var _returnData = function(q, msg) {
return {
tId: q.tId,
win: q.win,
data: q.data,
nodes: q.nodes,
msg: msg,
purge: function() {
_purge(this.tId);
}
};
};
var _get = function(nId, tId) {
var q = queues[tId],
n = (lang.isString(nId)) ? q.win.document.getElementById(nId) : nId;
if (!n) {
_fail(tId, "target node not found: " + nId);
}
return n;
};
/*
* The request failed, execute fail handler with whatever
* was accomplished. There isn't a failure case at the
* moment unless you count aborted transactions
* @method _fail
* @param id {string} the id of the request
* @private
*/
var _fail = function(id, msg) {
var q = queues[id];
// execute failure callback
if (q.onFailure) {
var sc=q.scope || q.win;
q.onFailure.call(sc, _returnData(q, msg));
}
};
/**
* The request is complete, so executing the requester's callback
* @method _finish
* @param id {string} the id of the request
* @private
*/
var _finish = function(id) {
var q = queues[id];
q.finished = true;
if (q.aborted) {
var msg = "transaction " + id + " was aborted";
_fail(id, msg);
return;
}
// execute success callback
if (q.onSuccess) {
var sc=q.scope || q.win;
q.onSuccess.call(sc, _returnData(q));
}
};
/**
* Timeout detected
* @method _timeout
* @param id {string} the id of the request
* @private
*/
var _timeout = function(id) {
var q = queues[id];
if (q.onTimeout) {
var sc=q.scope || q;
q.onTimeout.call(sc, _returnData(q));
}
};
/**
* Loads the next item for a given request
* @method _next
* @param id {string} the id of the request
* @param loaded {string} the url that was just loaded, if any
* @private
*/
var _next = function(id, loaded) {
var q = queues[id];
if (q.timer) {
// Y.log('cancel timer');
q.timer.cancel();
}
if (q.aborted) {
var msg = "transaction " + id + " was aborted";
_fail(id, msg);
return;
}
if (loaded) {
q.url.shift();
if (q.varName) {
q.varName.shift();
}
} else {
// This is the first pass: make sure the url is an array
q.url = (lang.isString(q.url)) ? [q.url] : q.url;
if (q.varName) {
q.varName = (lang.isString(q.varName)) ? [q.varName] : q.varName;
}
}
var w=q.win, d=w.document, h=d.getElementsByTagName("head")[0], n;
if (q.url.length === 0) {
// Safari 2.x workaround - There is no way to know when
// a script is ready in versions of Safari prior to 3.x.
// Adding an extra node reduces the problem, but doesn't
// eliminate it completely because the browser executes
// them asynchronously.
if (q.type === "script" && ua.webkit && ua.webkit < 420 &&
!q.finalpass && !q.varName) {
// Add another script node. This does not guarantee that the
// scripts will execute in order, but it does appear to fix the
// problem on fast connections more effectively than using an
// arbitrary timeout. It is possible that the browser does
// block subsequent script execution in this case for a limited
// time.
var extra = _scriptNode(null, q.win, q.attributes);
extra.innerHTML='YAHOO.util.Get._finalize("' + id + '");';
q.nodes.push(extra); h.appendChild(extra);
} else {
_finish(id);
}
return;
}
var url = q.url[0];
// if the url is undefined, this is probably a trailing comma problem in IE
if (!url) {
q.url.shift();
return _next(id);
}
if (q.timeout) {
// Y.log('create timer');
q.timer = lang.later(q.timeout, q, _timeout, id);
}
if (q.type === "script") {
n = _scriptNode(url, w, q.attributes);
} else {
n = _linkNode(url, w, q.attributes);
}
// track this node's load progress
_track(q.type, n, id, url, w, q.url.length);
// add the node to the queue so we can return it to the user supplied callback
q.nodes.push(n);
// add it to the head or insert it before 'insertBefore'
if (q.insertBefore) {
var s = _get(q.insertBefore, id);
if (s) {
s.parentNode.insertBefore(n, s);
}
} else {
h.appendChild(n);
}
// FireFox does not support the onload event for link nodes, so there is
// no way to make the css requests synchronous. This means that the css
// rules in multiple files could be applied out of order in this browser
// if a later request returns before an earlier one. Safari too.
if ((ua.webkit || ua.gecko) && q.type === "css") {
_next(id, url);
}
};
/**
* Removes processed queues and corresponding nodes
* @method _autoPurge
* @private
*/
var _autoPurge = function() {
if (purging) {
return;
}
purging = true;
for (var i in queues) {
var q = queues[i];
if (q.autopurge && q.finished) {
_purge(q.tId);
delete queues[i];
}
}
purging = false;
};
/**
* Removes the nodes for the specified queue
* @method _purge
* @private
*/
var _purge = function(tId) {
if (queues[tId]) {
var q = queues[tId],
nodes = q.nodes,
l = nodes.length,
d = q.win.document,
h = d.getElementsByTagName("head")[0],
sib, i, node, attr;
if (q.insertBefore) {
sib = _get(q.insertBefore, tId);
if (sib) {
h = sib.parentNode;
}
}
for (i=0; i<l; i=i+1) {
node = nodes[i];
if (node.clearAttributes) {
node.clearAttributes();
} else {
for (attr in node) {
delete node[attr];
}
}
h.removeChild(node);
}
q.nodes = [];
}
};
/**
* Saves the state for the request and begins loading
* the requested urls
* @method queue
* @param type {string} the type of node to insert
* @param url {string} the url to load
* @param opts the hash of options for this request
* @private
*/
var _queue = function(type, url, opts) {
var id = "q" + (qidx++);
opts = opts || {};
if (qidx % YAHOO.util.Get.PURGE_THRESH === 0) {
_autoPurge();
}
queues[id] = lang.merge(opts, {
tId: id,
type: type,
url: url,
finished: false,
aborted: false,
nodes: []
});
var q = queues[id];
q.win = q.win || window;
q.scope = q.scope || q.win;
q.autopurge = ("autopurge" in q) ? q.autopurge :
(type === "script") ? true : false;
if (opts.charset) {
q.attributes = q.attributes || {};
q.attributes.charset = opts.charset;
}
lang.later(0, q, _next, id);
return {
tId: id
};
};
/**
* Detects when a node has been loaded. In the case of
* script nodes, this does not guarantee that contained
* script is ready to use.
* @method _track
* @param type {string} the type of node to track
* @param n {HTMLElement} the node to track
* @param id {string} the id of the request
* @param url {string} the url that is being loaded
* @param win {Window} the targeted window
* @param qlength the number of remaining items in the queue,
* including this one
* @param trackfn {Function} function to execute when finished
* the default is _next
* @private
*/
var _track = function(type, n, id, url, win, qlength, trackfn) {
var f = trackfn || _next;
// IE supports the readystatechange event for script and css nodes
if (ua.ie) {
n.onreadystatechange = function() {
var rs = this.readyState;
if ("loaded" === rs || "complete" === rs) {
n.onreadystatechange = null;
f(id, url);
}
};
// webkit prior to 3.x is problemmatic
} else if (ua.webkit) {
if (type === "script") {
// Safari 3.x supports the load event for script nodes (DOM2)
if (ua.webkit >= 420) {
n.addEventListener("load", function() {
f(id, url);
});
// Nothing can be done with Safari < 3.x except to pause and hope
// for the best, particularly after last script is inserted. The
// scripts will always execute in the order they arrive, not
// necessarily the order in which they were inserted. To support
// script nodes with complete reliability in these browsers, script
// nodes either need to invoke a function in the window once they
// are loaded or the implementer needs to provide a well-known
// property that the utility can poll for.
} else {
// Poll for the existence of the named variable, if it
// was supplied.
var q = queues[id];
if (q.varName) {
var freq=YAHOO.util.Get.POLL_FREQ;
q.maxattempts = YAHOO.util.Get.TIMEOUT/freq;
q.attempts = 0;
q._cache = q.varName[0].split(".");
q.timer = lang.later(freq, q, function(o) {
var a=this._cache, l=a.length, w=this.win, i;
for (i=0; i<l; i=i+1) {
w = w[a[i]];
if (!w) {
// if we have exausted our attempts, give up
this.attempts++;
if (this.attempts++ > this.maxattempts) {
var msg = "Over retry limit, giving up";
q.timer.cancel();
_fail(id, msg);
} else {
}
return;
}
}
q.timer.cancel();
f(id, url);
}, null, true);
} else {
lang.later(YAHOO.util.Get.POLL_FREQ, null, f, [id, url]);
}
}
}
// FireFox and Opera support onload (but not DOM2 in FF) handlers for
// script nodes. Opera, but not FF, supports the onload event for link
// nodes.
} else {
n.onload = function() {
f(id, url);
};
}
};
return {
/**
* The default poll freqency in ms, when needed
* @property POLL_FREQ
* @static
* @type int
* @default 10
*/
POLL_FREQ: 10,
/**
* The number of request required before an automatic purge.
* property PURGE_THRESH
* @static
* @type int
* @default 20
*/
PURGE_THRESH: 20,
/**
* The length time to poll for varName when loading a script in
* Safari 2.x before the transaction fails.
* property TIMEOUT
* @static
* @type int
* @default 2000
*/
TIMEOUT: 2000,
/**
* Called by the the helper for detecting script load in Safari
* @method _finalize
* @param id {string} the transaction id
* @private
*/
_finalize: function(id) {
lang.later(0, null, _finish, id);
},
/**
* Abort a transaction
* @method abort
* @param {string|object} either the tId or the object returned from
* script() or css()
*/
abort: function(o) {
var id = (lang.isString(o)) ? o : o.tId;
var q = queues[id];
if (q) {
q.aborted = true;
}
},
/**
* Fetches and inserts one or more script nodes into the head
* of the current document or the document in a specified window.
*
* @method script
* @static
* @param url {string|string[]} the url or urls to the script(s)
* @param opts {object} Options:
* <dl>
* <dt>onSuccess</dt>
* <dd>
* callback to execute when the script(s) are finished loading
* The callback receives an object back with the following
* data:
* <dl>
* <dt>win</dt>
* <dd>the window the script(s) were inserted into</dd>
* <dt>data</dt>
* <dd>the data object passed in when the request was made</dd>
* <dt>nodes</dt>
* <dd>An array containing references to the nodes that were
* inserted</dd>
* <dt>purge</dt>
* <dd>A function that, when executed, will remove the nodes
* that were inserted</dd>
* <dt>
* </dl>
* </dd>
* <dt>onFailure</dt>
* <dd>
* callback to execute when the script load operation fails
* The callback receives an object back with the following
* data:
* <dl>
* <dt>win</dt>
* <dd>the window the script(s) were inserted into</dd>
* <dt>data</dt>
* <dd>the data object passed in when the request was made</dd>
* <dt>nodes</dt>
* <dd>An array containing references to the nodes that were
* inserted successfully</dd>
* <dt>purge</dt>
* <dd>A function that, when executed, will remove any nodes
* that were inserted</dd>
* <dt>
* </dl>
* </dd>
* <dt>onTimeout</dt>
* <dd>
* callback to execute when a timeout occurs.
* The callback receives an object back with the following
* data:
* <dl>
* <dt>win</dt>
* <dd>the window the script(s) were inserted into</dd>
* <dt>data</dt>
* <dd>the data object passed in when the request was made</dd>
* <dt>nodes</dt>
* <dd>An array containing references to the nodes that were
* inserted</dd>
* <dt>purge</dt>
* <dd>A function that, when executed, will remove the nodes
* that were inserted</dd>
* <dt>
* </dl>
* </dd>
* <dt>scope</dt>
* <dd>the execution context for the callbacks</dd>
* <dt>win</dt>
* <dd>a window other than the one the utility occupies</dd>
* <dt>autopurge</dt>
* <dd>
* setting to true will let the utilities cleanup routine purge
* the script once loaded
* </dd>
* <dt>data</dt>
* <dd>
* data that is supplied to the callback when the script(s) are
* loaded.
* </dd>
* <dt>varName</dt>
* <dd>
* variable that should be available when a script is finished
* loading. Used to help Safari 2.x and below with script load
* detection. The type of this property should match what was
* passed into the url parameter: if loading a single url, a
* string can be supplied. If loading multiple scripts, you
* must supply an array that contains the variable name for
* each script.
* </dd>
* <dt>insertBefore</dt>
* <dd>node or node id that will become the new node's nextSibling</dd>
* </dl>
* <dt>charset</dt>
* <dd>Node charset, deprecated, use 'attributes'</dd>
* <dt>attributes</dt>
* <dd>A hash of attributes to apply to dynamic nodes.</dd>
* <dt>timeout</dt>
* <dd>Number of milliseconds to wait before aborting and firing the timeout event</dd>
* <pre>
* // assumes yahoo, dom, and event are already on the page
* &nbsp;&nbsp;YAHOO.util.Get.script(
* &nbsp;&nbsp;["http://yui.yahooapis.com/2.7.0/build/dragdrop/dragdrop-min.js",
* &nbsp;&nbsp;&nbsp;"http://yui.yahooapis.com/2.7.0/build/animation/animation-min.js"], &#123;
* &nbsp;&nbsp;&nbsp;&nbsp;onSuccess: function(o) &#123;
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new YAHOO.util.DDProxy("dd1"); // also new o.reference("dd1"); would work
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.log("won't cause error because YAHOO is the scope");
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.log(o.nodes.length === 2) // true
* &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// o.purge(); // optionally remove the script nodes immediately
* &nbsp;&nbsp;&nbsp;&nbsp;&#125;,
* &nbsp;&nbsp;&nbsp;&nbsp;onFailure: function(o) &#123;
* &nbsp;&nbsp;&nbsp;&nbsp;&#125;,
* &nbsp;&nbsp;&nbsp;&nbsp;data: "foo",
* &nbsp;&nbsp;&nbsp;&nbsp;timeout: 10000, // 10 second timeout
* &nbsp;&nbsp;&nbsp;&nbsp;scope: YAHOO,
* &nbsp;&nbsp;&nbsp;&nbsp;// win: otherframe // target another window/frame
* &nbsp;&nbsp;&nbsp;&nbsp;autopurge: true // allow the utility to choose when to remove the nodes
* &nbsp;&nbsp;&#125;);
* </pre>
* @return {tId: string} an object containing info about the transaction
*/
script: function(url, opts) { return _queue("script", url, opts); },
/**
* Fetches and inserts one or more css link nodes into the
* head of the current document or the document in a specified
* window.
* @method css
* @static
* @param url {string} the url or urls to the css file(s)
* @param opts Options:
* <dl>
* <dt>onSuccess</dt>
* <dd>
* callback to execute when the css file(s) are finished loading
* The callback receives an object back with the following
* data:
* <dl>win</dl>
* <dd>the window the link nodes(s) were inserted into</dd>
* <dt>data</dt>
* <dd>the data object passed in when the request was made</dd>
* <dt>nodes</dt>
* <dd>An array containing references to the nodes that were
* inserted</dd>
* <dt>purge</dt>
* <dd>A function that, when executed, will remove the nodes
* that were inserted</dd>
* <dt>
* </dl>
* </dd>
* <dt>scope</dt>
* <dd>the execution context for the callbacks</dd>
* <dt>win</dt>
* <dd>a window other than the one the utility occupies</dd>
* <dt>data</dt>
* <dd>
* data that is supplied to the callbacks when the nodes(s) are
* loaded.
* </dd>
* <dt>insertBefore</dt>
* <dd>node or node id that will become the new node's nextSibling</dd>
* <dt>charset</dt>
* <dd>Node charset, deprecated, use 'attributes'</dd>
* <dt>attributes</dt>
* <dd>A hash of attributes to apply to dynamic nodes.</dd>
* </dl>
* <pre>
* YAHOO.util.Get.css("http://yui.yahooapis.com/2.7.0/build/menu/assets/skins/sam/menu.css");
* </pre>
* <pre>
* YAHOO.util.Get.css(["http://yui.yahooapis.com/2.7.0/build/menu/assets/skins/sam/menu.css",
* </pre>
* @return {tId: string} an object containing info about the transaction
*/
css: function(url, opts) {
return _queue("css", url, opts);
}
};
}();
YAHOO.register("get", YAHOO.util.Get, {version: "2.8.0r4", build: "2449"});
/**
* Provides dynamic loading for the YUI library. It includes the dependency
* info for the library, and will automatically pull in dependencies for
* the modules requested. It supports rollup files (such as utilities.js
* and yahoo-dom-event.js), and will automatically use these when
* appropriate in order to minimize the number of http connections
* required to load all of the dependencies.
*
* @module yuiloader
* @namespace YAHOO.util
*/
/**
* YUILoader provides dynamic loading for YUI.
* @class YAHOO.util.YUILoader
* @todo
* version management, automatic sandboxing
*/
(function() {
var Y=YAHOO, util=Y.util, lang=Y.lang, env=Y.env,
PROV = "_provides", SUPER = "_supersedes",
REQ = "expanded", AFTER = "_after";
var YUI = {
dupsAllowed: {'yahoo': true, 'get': true},
/*
* The library metadata for the current release The is the default
* value for YAHOO.util.YUILoader.moduleInfo
* @property YUIInfo
* @static
*/
info: {
// 'root': '2.5.2/build/',
// 'base': 'http://yui.yahooapis.com/2.5.2/build/',
'root': '2.8.0r4/build/',
'base': 'http://yui.yahooapis.com/2.8.0r4/build/',
'comboBase': 'http://yui.yahooapis.com/combo?',
'skin': {
'defaultSkin': 'sam',
'base': 'assets/skins/',
'path': 'skin.css',
'after': ['reset', 'fonts', 'grids', 'base'],
'rollup': 3
},
dupsAllowed: ['yahoo', 'get'],
'moduleInfo': {
'animation': {
'type': 'js',
'path': 'animation/animation-min.js',
'requires': ['dom', 'event']
},
'autocomplete': {
'type': 'js',
'path': 'autocomplete/autocomplete-min.js',
'requires': ['dom', 'event', 'datasource'],
'optional': ['connection', 'animation'],
'skinnable': true
},
'base': {
'type': 'css',
'path': 'base/base-min.css',
'after': ['reset', 'fonts', 'grids']
},
'button': {
'type': 'js',
'path': 'button/button-min.js',
'requires': ['element'],
'optional': ['menu'],
'skinnable': true
},
'calendar': {
'type': 'js',
'path': 'calendar/calendar-min.js',
'requires': ['event', 'dom'],
supersedes: ['datemeth'],
'skinnable': true
},
'carousel': {
'type': 'js',
'path': 'carousel/carousel-min.js',
'requires': ['element'],
'optional': ['animation'],
'skinnable': true
},
'charts': {
'type': 'js',
'path': 'charts/charts-min.js',
'requires': ['element', 'json', 'datasource', 'swf']
},
'colorpicker': {
'type': 'js',
'path': 'colorpicker/colorpicker-min.js',
'requires': ['slider', 'element'],
'optional': ['animation'],
'skinnable': true
},
'connection': {
'type': 'js',
'path': 'connection/connection-min.js',
'requires': ['event'],
'supersedes': ['connectioncore']
},
'connectioncore': {
'type': 'js',
'path': 'connection/connection_core-min.js',
'requires': ['event'],
'pkg': 'connection'
},
'container': {
'type': 'js',
'path': 'container/container-min.js',
'requires': ['dom', 'event'],
// button is also optional, but this creates a circular
// dependency when loadOptional is specified. button
// optionally includes menu, menu requires container.
'optional': ['dragdrop', 'animation', 'connection'],
'supersedes': ['containercore'],
'skinnable': true
},
'containercore': {
'type': 'js',
'path': 'container/container_core-min.js',
'requires': ['dom', 'event'],
'pkg': 'container'
},
'cookie': {
'type': 'js',
'path': 'cookie/cookie-min.js',
'requires': ['yahoo']
},
'datasource': {
'type': 'js',
'path': 'datasource/datasource-min.js',
'requires': ['event'],
'optional': ['connection']
},
'datatable': {
'type': 'js',
'path': 'datatable/datatable-min.js',
'requires': ['element', 'datasource'],
'optional': ['calendar', 'dragdrop', 'paginator'],
'skinnable': true
},
datemath: {
'type': 'js',
'path': 'datemath/datemath-min.js',
'requires': ['yahoo']
},
'dom': {
'type': 'js',
'path': 'dom/dom-min.js',
'requires': ['yahoo']
},
'dragdrop': {
'type': 'js',
'path': 'dragdrop/dragdrop-min.js',
'requires': ['dom', 'event']
},
'editor': {
'type': 'js',
'path': 'editor/editor-min.js',
'requires': ['menu', 'element', 'button'],
'optional': ['animation', 'dragdrop'],
'supersedes': ['simpleeditor'],
'skinnable': true
},
'element': {
'type': 'js',
'path': 'element/element-min.js',
'requires': ['dom', 'event'],
'optional': ['event-mouseenter', 'event-delegate']
},
'element-delegate': {
'type': 'js',
'path': 'element-delegate/element-delegate-min.js',
'requires': ['element']
},
'event': {
'type': 'js',
'path': 'event/event-min.js',
'requires': ['yahoo']
},
'event-simulate': {
'type': 'js',
'path': 'event-simulate/event-simulate-min.js',
'requires': ['event']
},
'event-delegate': {
'type': 'js',
'path': 'event-delegate/event-delegate-min.js',
'requires': ['event'],
'optional': ['selector']
},
'event-mouseenter': {
'type': 'js',
'path': 'event-mouseenter/event-mouseenter-min.js',
'requires': ['dom', 'event']
},
'fonts': {
'type': 'css',
'path': 'fonts/fonts-min.css'
},
'get': {
'type': 'js',
'path': 'get/get-min.js',
'requires': ['yahoo']
},
'grids': {
'type': 'css',
'path': 'grids/grids-min.css',
'requires': ['fonts'],
'optional': ['reset']
},
'history': {
'type': 'js',
'path': 'history/history-min.js',
'requires': ['event']
},
'imagecropper': {
'type': 'js',
'path': 'imagecropper/imagecropper-min.js',
'requires': ['dragdrop', 'element', 'resize'],
'skinnable': true
},
'imageloader': {
'type': 'js',
'path': 'imageloader/imageloader-min.js',
'requires': ['event', 'dom']
},
'json': {
'type': 'js',
'path': 'json/json-min.js',
'requires': ['yahoo']
},
'layout': {
'type': 'js',
'path': 'layout/layout-min.js',
'requires': ['element'],
'optional': ['animation', 'dragdrop', 'resize', 'selector'],
'skinnable': true
},
'logger': {
'type': 'js',
'path': 'logger/logger-min.js',
'requires': ['event', 'dom'],
'optional': ['dragdrop'],
'skinnable': true
},
'menu': {
'type': 'js',
'path': 'menu/menu-min.js',
'requires': ['containercore'],
'skinnable': true
},
'paginator': {
'type': 'js',
'path': 'paginator/paginator-min.js',
'requires': ['element'],
'skinnable': true
},
'profiler': {
'type': 'js',
'path': 'profiler/profiler-min.js',
'requires': ['yahoo']
},
'profilerviewer': {
'type': 'js',
'path': 'profilerviewer/profilerviewer-min.js',
'requires': ['profiler', 'yuiloader', 'element'],
'skinnable': true
},
'progressbar': {
'type': 'js',
'path': 'progressbar/progressbar-min.js',
'requires': ['element'],
'optional': ['animation'],
'skinnable': true
},
'reset': {
'type': 'css',
'path': 'reset/reset-min.css'
},
'reset-fonts-grids': {
'type': 'css',
'path': 'reset-fonts-grids/reset-fonts-grids.css',
'supersedes': ['reset', 'fonts', 'grids', 'reset-fonts'],
'rollup': 4
},
'reset-fonts': {
'type': 'css',
'path': 'reset-fonts/reset-fonts.css',
'supersedes': ['reset', 'fonts'],
'rollup': 2
},
'resize': {
'type': 'js',
'path': 'resize/resize-min.js',
'requires': ['dragdrop', 'element'],
'optional': ['animation'],
'skinnable': true
},
'selector': {
'type': 'js',
'path': 'selector/selector-min.js',
'requires': ['yahoo', 'dom']
},
'simpleeditor': {
'type': 'js',
'path': 'editor/simpleeditor-min.js',
'requires': ['element'],
'optional': ['containercore', 'menu', 'button', 'animation', 'dragdrop'],
'skinnable': true,
'pkg': 'editor'
},
'slider': {
'type': 'js',
'path': 'slider/slider-min.js',
'requires': ['dragdrop'],
'optional': ['animation'],
'skinnable': true
},
'storage': {
'type': 'js',
'path': 'storage/storage-min.js',
'requires': ['yahoo', 'event', 'cookie'],
'optional': ['swfstore']
},
'stylesheet': {
'type': 'js',
'path': 'stylesheet/stylesheet-min.js',
'requires': ['yahoo']
},
'swf': {
'type': 'js',
'path': 'swf/swf-min.js',
'requires': ['element'],
'supersedes': ['swfdetect']
},
'swfdetect': {
'type': 'js',
'path': 'swfdetect/swfdetect-min.js',
'requires': ['yahoo']
},
'swfstore': {
'type': 'js',
'path': 'swfstore/swfstore-min.js',
'requires': ['element', 'cookie', 'swf']
},
'tabview': {
'type': 'js',
'path': 'tabview/tabview-min.js',
'requires': ['element'],
'optional': ['connection'],
'skinnable': true
},
'treeview': {
'type': 'js',
'path': 'treeview/treeview-min.js',
'requires': ['event', 'dom'],
'optional': ['json', 'animation', 'calendar'],
'skinnable': true
},
'uploader': {
'type': 'js',
'path': 'uploader/uploader-min.js',
'requires': ['element']
},
'utilities': {
'type': 'js',
'path': 'utilities/utilities.js',
'supersedes': ['yahoo', 'event', 'dragdrop', 'animation', 'dom', 'connection', 'element', 'yahoo-dom-event', 'get', 'yuiloader', 'yuiloader-dom-event'],
'rollup': 8
},
'yahoo': {
'type': 'js',
'path': 'yahoo/yahoo-min.js'
},
'yahoo-dom-event': {
'type': 'js',
'path': 'yahoo-dom-event/yahoo-dom-event.js',
'supersedes': ['yahoo', 'event', 'dom'],
'rollup': 3
},
'yuiloader': {
'type': 'js',
'path': 'yuiloader/yuiloader-min.js',
'supersedes': ['yahoo', 'get']
},
'yuiloader-dom-event': {
'type': 'js',
'path': 'yuiloader-dom-event/yuiloader-dom-event.js',
'supersedes': ['yahoo', 'dom', 'event', 'get', 'yuiloader', 'yahoo-dom-event'],
'rollup': 5
},
'yuitest': {
'type': 'js',
'path': 'yuitest/yuitest-min.js',
'requires': ['logger'],
'optional': ['event-simulate'],
'skinnable': true
}
}
}
,
ObjectUtil: {
appendArray: function(o, a) {
if (a) {
for (var i=0; i<a.length; i=i+1) {
o[a[i]] = true;
}
}
},
keys: function(o, ordered) {
var a=[], i;
for (i in o) {
if (lang.hasOwnProperty(o, i)) {
a.push(i);
}
}
return a;
}
},
ArrayUtil: {
appendArray: function(a1, a2) {
Array.prototype.push.apply(a1, a2);
/*
for (var i=0; i<a2.length; i=i+1) {
a1.push(a2[i]);
}
*/
},
indexOf: function(a, val) {
for (var i=0; i<a.length; i=i+1) {
if (a[i] === val) {
return i;
}
}
return -1;
},
toObject: function(a) {
var o = {};
for (var i=0; i<a.length; i=i+1) {
o[a[i]] = true;
}
return o;
},
/*
* Returns a unique array. Does not maintain order, which is fine
* for this application, and performs better than it would if it
* did.
*/
uniq: function(a) {
return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));
}
}
};
YAHOO.util.YUILoader = function(o) {
/**
* Internal callback to handle multiple internal insert() calls
* so that css is inserted prior to js
* @property _internalCallback
* @private
*/
this._internalCallback = null;
/**
* Use the YAHOO environment listener to detect script load. This
* is only switched on for Safari 2.x and below.
* @property _useYahooListener
* @private
*/
this._useYahooListener = false;
/**
* Callback that will be executed when the loader is finished
* with an insert
* @method onSuccess
* @type function
*/
this.onSuccess = null;
/**
* Callback that will be executed if there is a failure
* @method onFailure
* @type function
*/
this.onFailure = Y.log;
/**
* Callback that will be executed each time a new module is loaded
* @method onProgress
* @type function
*/
this.onProgress = null;
/**
* Callback that will be executed if a timeout occurs
* @method onTimeout
* @type function
*/
this.onTimeout = null;
/**
* The execution scope for all callbacks
* @property scope
* @default this
*/
this.scope = this;
/**
* Data that is passed to all callbacks
* @property data
*/
this.data = null;
/**
* Node reference or id where new nodes should be inserted before
* @property insertBefore
* @type string|HTMLElement
*/
this.insertBefore = null;
/**
* The charset attribute for inserted nodes
* @property charset
* @type string
* @default utf-8
*/
this.charset = null;
/**
* The name of the variable in a sandbox or script node
* (for external script support in Safari 2.x and earlier)
* to reference when the load is complete. If this variable
* is not available in the specified scripts, the operation will
* fail.
* @property varName
* @type string
*/
this.varName = null;
/**
* The base directory.
* @property base
* @type string
* @default http://yui.yahooapis.com/[YUI VERSION]/build/
*/
this.base = YUI.info.base;
/**
* Base path for the combo service
* @property comboBase
* @type string
* @default http://yui.yahooapis.com/combo?
*/
this.comboBase = YUI.info.comboBase;
/**
* If configured, YUI will use the the combo handler on the
* Yahoo! CDN to pontentially reduce the number of http requests
* required.
* @property combine
* @type boolean
* @default false
*/
// this.combine = (o && !('base' in o));
this.combine = false;
/**
* Root path to prepend to module path for the combo
* service
* @property root
* @type string
* @default [YUI VERSION]/build/
*/
this.root = YUI.info.root;
/**
* Timeout value in milliseconds. If set, this value will be used by
* the get utility. the timeout event will fire if
* a timeout occurs.
* @property timeout
* @type int
*/
this.timeout = 0;
/**
* A list of modules that should not be loaded, even if
* they turn up in the dependency tree
* @property ignore
* @type string[]
*/
this.ignore = null;
/**
* A list of modules that should always be loaded, even
* if they have already been inserted into the page.
* @property force
* @type string[]
*/
this.force = null;
/**
* Should we allow rollups
* @property allowRollup
* @type boolean
* @default true
*/
this.allowRollup = true;
/**
* A filter to apply to result urls. This filter will modify the default
* path for all modules. The default path for the YUI library is the
* minified version of the files (e.g., event-min.js). The filter property
* can be a predefined filter or a custom filter. The valid predefined
* filters are:
* <dl>
* <dt>DEBUG</dt>
* <dd>Selects the debug versions of the library (e.g., event-debug.js).
* This option will automatically include the logger widget</dd>
* <dt>RAW</dt>
* <dd>Selects the non-minified version of the library (e.g., event.js).
* </dl>
* You can also define a custom filter, which must be an object literal
* containing a search expression and a replace string:
* <pre>
* myFilter: &#123;
* 'searchExp': "-min\\.js",
* 'replaceStr': "-debug.js"
* &#125;
* </pre>
* @property filter
* @type string|{searchExp: string, replaceStr: string}
*/
this.filter = null;
/**
* The list of requested modules
* @property required
* @type {string: boolean}
*/
this.required = {};
/**
* The library metadata
* @property moduleInfo
*/
this.moduleInfo = lang.merge(YUI.info.moduleInfo);
/**
* List of rollup files found in the library metadata
* @property rollups
*/
this.rollups = null;
/**
* Whether or not to load optional dependencies for
* the requested modules
* @property loadOptional
* @type boolean
* @default false
*/
this.loadOptional = false;
/**
* All of the derived dependencies in sorted order, which
* will be populated when either calculate() or insert()
* is called
* @property sorted
* @type string[]
*/
this.sorted = [];
/**
* Set when beginning to compute the dependency tree.
* Composed of what YAHOO reports to be loaded combined
* with what has been loaded by the tool
* @propery loaded
* @type {string: boolean}
*/
this.loaded = {};
/**
* Flag to indicate the dependency tree needs to be recomputed
* if insert is called again.
* @property dirty
* @type boolean
* @default true
*/
this.dirty = true;
/**
* List of modules inserted by the utility
* @property inserted
* @type {string: boolean}
*/
this.inserted = {};
/**
* Provides the information used to skin the skinnable components.
* The following skin definition would result in 'skin1' and 'skin2'
* being loaded for calendar (if calendar was requested), and
* 'sam' for all other skinnable components:
*
* <code>
* skin: {
*
* // The default skin, which is automatically applied if not
* // overriden by a component-specific skin definition.
* // Change this in to apply a different skin globally
* defaultSkin: 'sam',
*
* // This is combined with the loader base property to get
* // the default root directory for a skin. ex:
* // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
* base: 'assets/skins/',
*
* // The name of the rollup css file for the skin
* path: 'skin.css',
*
* // The number of skinnable components requested that are
* // required before using the rollup file rather than the
* // individual component css files
* rollup: 3,
*
* // Any component-specific overrides can be specified here,
* // making it possible to load different skins for different
* // components. It is possible to load more than one skin
* // for a given component as well.
* overrides: {
* calendar: ['skin1', 'skin2']
* }
* }
* </code>
* @property skin
*/
var self = this;
env.listeners.push(function(m) {
if (self._useYahooListener) {
//Y.log("YAHOO listener: " + m.name);
self.loadNext(m.name);
}
});
this.skin = lang.merge(YUI.info.skin);
this._config(o);
};
Y.util.YUILoader.prototype = {
FILTERS: {
RAW: {
'searchExp': "-min\\.js",
'replaceStr': ".js"
},
DEBUG: {
'searchExp': "-min\\.js",
'replaceStr': "-debug.js"
}
},
SKIN_PREFIX: "skin-",
_config: function(o) {
// apply config values
if (o) {
for (var i in o) {
if (lang.hasOwnProperty(o, i)) {
if (i == "require") {
this.require(o[i]);
} else {
this[i] = o[i];
}
}
}
}
// fix filter
var f = this.filter;
if (lang.isString(f)) {
f = f.toUpperCase();
// the logger must be available in order to use the debug
// versions of the library
if (f === "DEBUG") {
this.require("logger");
}
// hack to handle a a bug where LogWriter is being instantiated
// at load time, and the loader has no way to sort above it
// at the moment.
if (!Y.widget.LogWriter) {
Y.widget.LogWriter = function() {
return Y;
};
}
this.filter = this.FILTERS[f];
}
},
/** Add a new module to the component metadata.
* <dl>
* <dt>name:</dt> <dd>required, the component name</dd>
* <dt>type:</dt> <dd>required, the component type (js or css)</dd>
* <dt>path:</dt> <dd>required, the path to the script from "base"</dd>
* <dt>requires:</dt> <dd>array of modules required by this component</dd>
* <dt>optional:</dt> <dd>array of optional modules for this component</dd>
* <dt>supersedes:</dt> <dd>array of the modules this component replaces</dd>
* <dt>after:</dt> <dd>array of modules the components which, if present, should be sorted above this one</dd>
* <dt>rollup:</dt> <dd>the number of superseded modules required for automatic rollup</dd>
* <dt>fullpath:</dt> <dd>If fullpath is specified, this is used instead of the configured base + path</dd>
* <dt>skinnable:</dt> <dd>flag to determine if skin assets should automatically be pulled in</dd>
* </dl>
* @method addModule
* @param o An object containing the module data
* @return {boolean} true if the module was added, false if
* the object passed in did not provide all required attributes
*/
addModule: function(o) {
if (!o || !o.name || !o.type || (!o.path && !o.fullpath)) {
return false;
}
o.ext = ('ext' in o) ? o.ext : true;
o.requires = o.requires || [];
this.moduleInfo[o.name] = o;
this.dirty = true;
return true;
},
/**
* Add a requirement for one or more module
* @method require
* @param what {string[] | string*} the modules to load
*/
require: function(what) {
var a = (typeof what === "string") ? arguments : what;
this.dirty = true;
YUI.ObjectUtil.appendArray(this.required, a);
},
/**
* Adds the skin def to the module info
* @method _addSkin
* @param skin {string} the name of the skin
* @param mod {string} the name of the module
* @return {string} the module name for the skin
* @private
*/
_addSkin: function(skin, mod) {
// Add a module definition for the skin rollup css
var name = this.formatSkin(skin), info = this.moduleInfo,
sinf = this.skin, ext = info[mod] && info[mod].ext;
// Y.log('ext? ' + mod + ": " + ext);
if (!info[name]) {
// Y.log('adding skin ' + name);
this.addModule({
'name': name,
'type': 'css',
'path': sinf.base + skin + '/' + sinf.path,
//'supersedes': '*',
'after': sinf.after,
'rollup': sinf.rollup,
'ext': ext
});
}
// Add a module definition for the module-specific skin css
if (mod) {
name = this.formatSkin(skin, mod);
if (!info[name]) {
var mdef = info[mod], pkg = mdef.pkg || mod;
// Y.log('adding skin ' + name);
this.addModule({
'name': name,
'type': 'css',
'after': sinf.after,
'path': pkg + '/' + sinf.base + skin + '/' + mod + '.css',
'ext': ext
});
}
}
return name;
},
/**
* Returns an object containing properties for all modules required
* in order to load the requested module
* @method getRequires
* @param mod The module definition from moduleInfo
*/
getRequires: function(mod) {
if (!mod) {
return [];
}
if (!this.dirty && mod.expanded) {
return mod.expanded;
}
mod.requires=mod.requires || [];
var i, d=[], r=mod.requires, o=mod.optional, info=this.moduleInfo, m;
for (i=0; i<r.length; i=i+1) {
d.push(r[i]);
m = info[r[i]];
YUI.ArrayUtil.appendArray(d, this.getRequires(m));
// add existing skins for skinnable modules as well. The only
// way to do this is go through the list of required items (this
// assumes that _skin is called before getRequires is called on
// the module.
// if (m.skinnable) {
// var req=this.required, l=req.length;
// for (var j=0; j<l; j=j+1) {
// // YAHOO.log('checking ' + r[j]);
// if (req[j].indexOf(r[j]) > -1) {
// // YAHOO.log('adding ' + r[j]);
// d.push(req[j]);
// }
// }
// }
}
if (o && this.loadOptional) {
for (i=0; i<o.length; i=i+1) {
d.push(o[i]);
YUI.ArrayUtil.appendArray(d, this.getRequires(info[o[i]]));
}
}
mod.expanded = YUI.ArrayUtil.uniq(d);
return mod.expanded;
},
/**
* Returns an object literal of the modules the supplied module satisfies
* @method getProvides
* @param name{string} The name of the module
* @param notMe {string} don't add this module name, only include superseded modules
* @return what this module provides
*/
getProvides: function(name, notMe) {
var addMe = !(notMe), ckey = (addMe) ? PROV : SUPER,
m = this.moduleInfo[name], o = {};
if (!m) {
return o;
}
if (m[ckey]) {
// Y.log('cached: ' + name + ' ' + ckey + ' ' + lang.dump(this.moduleInfo[name][ckey], 0));
return m[ckey];
}
var s = m.supersedes, done={}, me = this;
// use worker to break cycles
var add = function(mm) {
if (!done[mm]) {
// Y.log(name + ' provides worker trying: ' + mm);
done[mm] = true;
// we always want the return value normal behavior
// (provides) for superseded modules.
lang.augmentObject(o, me.getProvides(mm));
}
// else {
// Y.log(name + ' provides worker skipping done: ' + mm);
// }
};
// calculate superseded modules
if (s) {
for (var i=0; i<s.length; i=i+1) {
add(s[i]);
}
}
// supersedes cache
m[SUPER] = o;
// provides cache
m[PROV] = lang.merge(o);
m[PROV][name] = true;
// Y.log(name + " supersedes " + lang.dump(m[SUPER], 0));
// Y.log(name + " provides " + lang.dump(m[PROV], 0));
return m[ckey];
},
/**
* Calculates the dependency tree, the result is stored in the sorted
* property
* @method calculate
* @param o optional options object
*/
calculate: function(o) {
if (o || this.dirty) {
this._config(o);
this._setup();
this._explode();
// this._skin(); // deprecated
if (this.allowRollup) {
this._rollup();
}
this._reduce();
this._sort();
// Y.log("after calculate: " + lang.dump(this.required));
this.dirty = false;
}
},
/**
* Investigates the current YUI configuration on the page. By default,
* modules already detected will not be loaded again unless a force
* option is encountered. Called by calculate()
* @method _setup
* @private
*/
_setup: function() {
var info = this.moduleInfo, name, i, j;
// Create skin modules
for (name in info) {
if (lang.hasOwnProperty(info, name)) {
var m = info[name];
if (m && m.skinnable) {
// Y.log("skinning: " + name);
var o=this.skin.overrides, smod;
if (o && o[name]) {
for (i=0; i<o[name].length; i=i+1) {
smod = this._addSkin(o[name][i], name);
}
} else {
smod = this._addSkin(this.skin.defaultSkin, name);
}
m.requires.push(smod);
}
}
}
var l = lang.merge(this.inserted); // shallow clone
if (!this._sandbox) {
l = lang.merge(l, env.modules);
}
// Y.log("Already loaded stuff: " + lang.dump(l, 0));
// add the ignore list to the list of loaded packages
if (this.ignore) {
YUI.ObjectUtil.appendArray(l, this.ignore);
}
// remove modules on the force list from the loaded list
if (this.force) {
for (i=0; i<this.force.length; i=i+1) {
if (this.force[i] in l) {
delete l[this.force[i]];
}
}
}
// expand the list to include superseded modules
for (j in l) {
// Y.log("expanding: " + j);
if (lang.hasOwnProperty(l, j)) {
lang.augmentObject(l, this.getProvides(j));
}
}
// Y.log("loaded expanded: " + lang.dump(l, 0));
this.loaded = l;
},
/**
* Inspects the required modules list looking for additional
* dependencies. Expands the required list to include all
* required modules. Called by calculate()
* @method _explode
* @private
*/
_explode: function() {
var r=this.required, i, mod;
for (i in r) {
if (lang.hasOwnProperty(r, i)) {
mod = this.moduleInfo[i];
if (mod) {
var req = this.getRequires(mod);
if (req) {
YUI.ObjectUtil.appendArray(r, req);
}
}
}
}
},
/**
* Sets up the requirements for the skin assets if any of the
* requested modules are skinnable
* @method _skin
* @private
* @deprecated skin modules are generated for all skinnable
* components during _setup(), and the components
* are configured to require the skin.
*/
_skin: function() {
},
/**
* Returns the skin module name for the specified skin name. If a
* module name is supplied, the returned skin module name is
* specific to the module passed in.
* @method formatSkin
* @param skin {string} the name of the skin
* @param mod {string} optional: the name of a module to skin
* @return {string} the full skin module name
*/
formatSkin: function(skin, mod) {
var s = this.SKIN_PREFIX + skin;
if (mod) {
s = s + "-" + mod;
}
return s;
},
/**
* Reverses <code>formatSkin</code>, providing the skin name and
* module name if the string matches the pattern for skins.
* @method parseSkin
* @param mod {string} the module name to parse
* @return {skin: string, module: string} the parsed skin name
* and module name, or null if the supplied string does not match
* the skin pattern
*/
parseSkin: function(mod) {
if (mod.indexOf(this.SKIN_PREFIX) === 0) {
var a = mod.split("-");
return {skin: a[1], module: a[2]};
}
return null;
},
/**
* Look for rollup packages to determine if all of the modules a
* rollup supersedes are required. If so, include the rollup to
* help reduce the total number of connections required. Called
* by calculate()
* @method _rollup
* @private
*/
_rollup: function() {
var i, j, m, s, rollups={}, r=this.required, roll,
info = this.moduleInfo;
// find and cache rollup modules
if (this.dirty || !this.rollups) {
for (i in info) {
if (lang.hasOwnProperty(info, i)) {
m = info[i];
//if (m && m.rollup && m.supersedes) {
if (m && m.rollup) {
rollups[i] = m;
}
}
}
this.rollups = rollups;
}
// make as many passes as needed to pick up rollup rollups
for (;;) {
var rolled = false;
// go through the rollup candidates
for (i in rollups) {
// there can be only one
if (!r[i] && !this.loaded[i]) {
m =info[i]; s = m.supersedes; roll=false;
if (!m.rollup) {
continue;
}
var skin = (m.ext) ? false : this.parseSkin(i), c = 0;
// Y.log('skin? ' + i + ": " + skin);
if (skin) {
for (j in r) {
if (lang.hasOwnProperty(r, j)) {
if (i !== j && this.parseSkin(j)) {
c++;
roll = (c >= m.rollup);
if (roll) {
// Y.log("skin rollup " + lang.dump(r));
break;
}
}
}
}
} else {
// check the threshold
for (j=0;j<s.length;j=j+1) {
// if the superseded module is loaded, we can't load the rollup
if (this.loaded[s[j]] && (!YUI.dupsAllowed[s[j]])) {
roll = false;
break;
// increment the counter if this module is required. if we are
// beyond the rollup threshold, we will use the rollup module
} else if (r[s[j]]) {
c++;
roll = (c >= m.rollup);
if (roll) {
// Y.log("over thresh " + c + ", " + lang.dump(r));
break;
}
}
}
}
if (roll) {
// Y.log("rollup: " + i + ", " + lang.dump(this, 1));
// add the rollup
r[i] = true;
rolled = true;
// expand the rollup's dependencies
this.getRequires(m);
}
}
}
// if we made it here w/o rolling up something, we are done
if (!rolled) {
break;
}
}
},
/**
* Remove superceded modules and loaded modules. Called by
* calculate() after we have the mega list of all dependencies
* @method _reduce
* @private
*/
_reduce: function() {
var i, j, s, m, r=this.required;
for (i in r) {
// remove if already loaded
if (i in this.loaded) {
delete r[i];
// remove anything this module supersedes
} else {
var skinDef = this.parseSkin(i);
if (skinDef) {
//YAHOO.log("skin found in reduce: " + skinDef.skin + ", " + skinDef.module);
// the skin rollup will not have a module name
if (!skinDef.module) {
var skin_pre = this.SKIN_PREFIX + skinDef.skin;
//YAHOO.log("skin_pre: " + skin_pre);
for (j in r) {
if (lang.hasOwnProperty(r, j)) {
m = this.moduleInfo[j];
var ext = m && m.ext;
if (!ext && j !== i && j.indexOf(skin_pre) > -1) {
// Y.log ("removing component skin: " + j);
delete r[j];
}
}
}
}
} else {
m = this.moduleInfo[i];
s = m && m.supersedes;
if (s) {
for (j=0; j<s.length; j=j+1) {
if (s[j] in r) {
delete r[s[j]];
}
}
}
}
}
}
},
_onFailure: function(msg) {
YAHOO.log('Failure', 'info', 'loader');
var f = this.onFailure;
if (f) {
f.call(this.scope, {
msg: 'failure: ' + msg,
data: this.data,
success: false
});
}
},
_onTimeout: function() {
YAHOO.log('Timeout', 'info', 'loader');
var f = this.onTimeout;
if (f) {
f.call(this.scope, {
msg: 'timeout',
data: this.data,
success: false
});
}
},
/**
* Sorts the dependency tree. The last step of calculate()
* @method _sort
* @private
*/
_sort: function() {
// create an indexed list
var s=[], info=this.moduleInfo, loaded=this.loaded,
checkOptional=!this.loadOptional, me = this;
// returns true if b is not loaded, and is required
// directly or by means of modules it supersedes.
var requires = function(aa, bb) {
var mm=info[aa];
if (loaded[bb] || !mm) {
return false;
}
var ii,
rr = mm.expanded,
after = mm.after,
other = info[bb],
optional = mm.optional;
// check if this module requires the other directly
if (rr && YUI.ArrayUtil.indexOf(rr, bb) > -1) {
return true;
}
// check if this module should be sorted after the other
if (after && YUI.ArrayUtil.indexOf(after, bb) > -1) {
return true;
}
// if loadOptional is not specified, optional dependencies still
// must be sorted correctly when present.
if (checkOptional && optional && YUI.ArrayUtil.indexOf(optional, bb) > -1) {
return true;
}
// check if this module requires one the other supersedes
var ss=info[bb] && info[bb].supersedes;
if (ss) {
for (ii=0; ii<ss.length; ii=ii+1) {
if (requires(aa, ss[ii])) {
return true;
}
}
}
// var ss=me.getProvides(bb, true);
// if (ss) {
// for (ii in ss) {
// if (requires(aa, ii)) {
// return true;
// }
// }
// }
// external css files should be sorted below yui css
if (mm.ext && mm.type == 'css' && !other.ext && other.type == 'css') {
return true;
}
return false;
};
// get the required items out of the obj into an array so we
// can sort
for (var i in this.required) {
if (lang.hasOwnProperty(this.required, i)) {
s.push(i);
}
}
// pointer to the first unsorted item
var p=0;
// keep going until we make a pass without moving anything
for (;;) {
var l=s.length, a, b, j, k, moved=false;
// start the loop after items that are already sorted
for (j=p; j<l; j=j+1) {
// check the next module on the list to see if its
// dependencies have been met
a = s[j];
// check everything below current item and move if we
// find a requirement for the current item
for (k=j+1; k<l; k=k+1) {
if (requires(a, s[k])) {
// extract the dependency so we can move it up
b = s.splice(k, 1);
// insert the dependency above the item that
// requires it
s.splice(j, 0, b[0]);
moved = true;
break;
}
}
// jump out of loop if we moved something
if (moved) {
break;
// this item is sorted, move our pointer and keep going
} else {
p = p + 1;
}
}
// when we make it here and moved is false, we are
// finished sorting
if (!moved) {
break;
}
}
this.sorted = s;
},
toString: function() {
var o = {
type: "YUILoader",
base: this.base,
filter: this.filter,
required: this.required,
loaded: this.loaded,
inserted: this.inserted
};
lang.dump(o, 1);
},
_combine: function() {
this._combining = [];
var self = this,
s=this.sorted,
len = s.length,
js = this.comboBase,
css = this.comboBase,
target,
startLen = js.length,
i, m, type = this.loadType;
YAHOO.log('type ' + type);
for (i=0; i<len; i=i+1) {
m = this.moduleInfo[s[i]];
if (m && !m.ext && (!type || type === m.type)) {
target = this.root + m.path;
// if (i < len-1) {
target += '&';
// }
if (m.type == 'js') {
js += target;
} else {
css += target;
}
// YAHOO.log(target);
this._combining.push(s[i]);
}
}
if (this._combining.length) {
YAHOO.log('Attempting to combine: ' + this._combining, "info", "loader");
var callback=function(o) {
// YAHOO.log('Combo complete: ' + o.data, "info", "loader");
// this._combineComplete = true;
var c=this._combining, len=c.length, i, m;
for (i=0; i<len; i=i+1) {
this.inserted[c[i]] = true;
}
this.loadNext(o.data);
},
loadScript = function() {
// YAHOO.log('combining js: ' + js);
if (js.length > startLen) {
YAHOO.util.Get.script(self._filter(js), {
data: self._loading,
onSuccess: callback,
onFailure: self._onFailure,
onTimeout: self._onTimeout,
insertBefore: self.insertBefore,
charset: self.charset,
timeout: self.timeout,
scope: self
});
}
};
// load the css first
// YAHOO.log('combining css: ' + css);
if (css.length > startLen) {
YAHOO.util.Get.css(this._filter(css), {
data: this._loading,
onSuccess: loadScript,
onFailure: this._onFailure,
onTimeout: this._onTimeout,
insertBefore: this.insertBefore,
charset: this.charset,
timeout: this.timeout,
scope: self
});
} else {
loadScript();
}
return;
} else {
// this._combineComplete = true;
this.loadNext(this._loading);
}
},
/**
* inserts the requested modules and their dependencies.
* <code>type</code> can be "js" or "css". Both script and
* css are inserted if type is not provided.
* @method insert
* @param o optional options object
* @param type {string} the type of dependency to insert
*/
insert: function(o, type) {
// if (o) {
// Y.log("insert: " + lang.dump(o, 1) + ", " + type);
// } else {
// Y.log("insert: " + this.toString() + ", " + type);
// }
// build the dependency list
this.calculate(o);
// set a flag to indicate the load has started
this._loading = true;
// flag to indicate we are done with the combo service
// and any additional files will need to be loaded
// individually
// this._combineComplete = false;
// keep the loadType (js, css or undefined) cached
this.loadType = type;
if (this.combine) {
return this._combine();
}
if (!type) {
// Y.log("trying to load css first");
var self = this;
this._internalCallback = function() {
self._internalCallback = null;
self.insert(null, "js");
};
this.insert(null, "css");
return;
}
// start the load
this.loadNext();
},
/**
* Interns the script for the requested modules. The callback is
* provided a reference to the sandboxed YAHOO object. This only
* applies to the script: css can not be sandboxed; css will be
* loaded into the page normally if specified.
* @method sandbox
* @param callback {Function} the callback to exectued when the load is
* complete.
*/
sandbox: function(o, type) {
// if (o) {
// YAHOO.log("sandbox: " + lang.dump(o, 1) + ", " + type);
// } else {
// YAHOO.log("sandbox: " + this.toString() + ", " + type);
// }
this._config(o);
if (!this.onSuccess) {
throw new Error("You must supply an onSuccess handler for your sandbox");
}
this._sandbox = true;
var self = this;
// take care of any css first (this can't be sandboxed)
if (!type || type !== "js") {
this._internalCallback = function() {
self._internalCallback = null;
self.sandbox(null, "js");
};
this.insert(null, "css");
return;
}
// get the connection manager if not on the page
if (!util.Connect) {
// get a new loader instance to load connection.
var ld = new YAHOO.util.YUILoader();
ld.insert({
base: this.base,
filter: this.filter,
require: "connection",
insertBefore: this.insertBefore,
charset: this.charset,
onSuccess: function() {
this.sandbox(null, "js");
},
scope: this
}, "js");
return;
}
this._scriptText = [];
this._loadCount = 0;
this._stopCount = this.sorted.length;
this._xhr = [];
this.calculate();
var s=this.sorted, l=s.length, i, m, url;
for (i=0; i<l; i=i+1) {
m = this.moduleInfo[s[i]];
// undefined modules cause a failure
if (!m) {
this._onFailure("undefined module " + m);
for (var j=0;j<this._xhr.length;j=j+1) {
this._xhr[j].abort();
}
return;
}
// css files should be done
if (m.type !== "js") {
this._loadCount++;
continue;
}
url = m.fullpath;
url = (url) ? this._filter(url) : this._url(m.path);
// YAHOO.log("xhr request: " + url + ", " + i);
var xhrData = {
success: function(o) {
var idx=o.argument[0], name=o.argument[2];
// store the response in the position it was requested
this._scriptText[idx] = o.responseText;
// YAHOO.log("received: " + o.responseText.substr(0, 100) + ", " + idx);
if (this.onProgress) {
this.onProgress.call(this.scope, {
name: name,
scriptText: o.responseText,
xhrResponse: o,
data: this.data
});
}
// only generate the sandbox once everything is loaded
this._loadCount++;
if (this._loadCount >= this._stopCount) {
// the variable to find
var v = this.varName || "YAHOO";
// wrap the contents of the requested modules in an anonymous function
var t = "(function() {\n";
// return the locally scoped reference.
var b = "\nreturn " + v + ";\n})();";
var ref = eval(t + this._scriptText.join("\n") + b);
this._pushEvents(ref);
if (ref) {
this.onSuccess.call(this.scope, {
reference: ref,
data: this.data
});
} else {
this._onFailure.call(this.varName + " reference failure");
}
}
},
failure: function(o) {
this.onFailure.call(this.scope, {
msg: "XHR failure",
xhrResponse: o,
data: this.data
});
},
scope: this,
// module index, module name, sandbox name
argument: [i, url, s[i]]
};
this._xhr.push(util.Connect.asyncRequest('GET', url, xhrData));
}
},
/**
* Executed every time a module is loaded, and if we are in a load
* cycle, we attempt to load the next script. Public so that it
* is possible to call this if using a method other than
* YAHOO.register to determine when scripts are fully loaded
* @method loadNext
* @param mname {string} optional the name of the module that has
* been loaded (which is usually why it is time to load the next
* one)
*/
loadNext: function(mname) {
// It is possible that this function is executed due to something
// else one the page loading a YUI module. Only react when we
// are actively loading something
if (!this._loading) {
return;
}
if (mname) {
// if the module that was just loaded isn't what we were expecting,
// continue to wait
if (mname !== this._loading) {
return;
}
// YAHOO.log("loadNext executing, just loaded " + mname);
// The global handler that is called when each module is loaded
// will pass that module name to this function. Storing this
// data to avoid loading the same module multiple times
this.inserted[mname] = true;
if (this.onProgress) {
this.onProgress.call(this.scope, {
name: mname,
data: this.data
});
}
//var o = this.getProvides(mname);
//this.inserted = lang.merge(this.inserted, o);
}
var s=this.sorted, len=s.length, i, m;
for (i=0; i<len; i=i+1) {
// This.inserted keeps track of what the loader has loaded
if (s[i] in this.inserted) {
// YAHOO.log(s[i] + " alread loaded ");
continue;
}
// Because rollups will cause multiple load notifications
// from YAHOO, loadNext may be called multiple times for
// the same module when loading a rollup. We can safely
// skip the subsequent requests
if (s[i] === this._loading) {
// YAHOO.log("still loading " + s[i] + ", waiting");
return;
}
// log("inserting " + s[i]);
m = this.moduleInfo[s[i]];
if (!m) {
this.onFailure.call(this.scope, {
msg: "undefined module " + m,
data: this.data
});
return;
}
// The load type is stored to offer the possibility to load
// the css separately from the script.
if (!this.loadType || this.loadType === m.type) {
this._loading = s[i];
//YAHOO.log("attempting to load " + s[i] + ", " + this.base);
var fn=(m.type === "css") ? util.Get.css : util.Get.script,
url = m.fullpath,
self=this,
c=function(o) {
self.loadNext(o.data);
};
url = (url) ? this._filter(url) : this._url(m.path);
// safari 2.x or lower, script, and part of YUI
if (env.ua.webkit && env.ua.webkit < 420 && m.type === "js" &&
!m.varName) {
//YUI.info.moduleInfo[s[i]]) {
//YAHOO.log("using YAHOO env " + s[i] + ", " + m.varName);
c = null;
this._useYahooListener = true;
}
fn(url, {
data: s[i],
onSuccess: c,
onFailure: this._onFailure,
onTimeout: this._onTimeout,
insertBefore: this.insertBefore,
charset: this.charset,
timeout: this.timeout,
varName: m.varName,
scope: self
});
return;
}
}
// we are finished
this._loading = null;
// internal callback for loading css first
if (this._internalCallback) {
var f = this._internalCallback;
this._internalCallback = null;
f.call(this);
} else if (this.onSuccess) {
this._pushEvents();
this.onSuccess.call(this.scope, {
data: this.data
});
}
},
/**
* In IE, the onAvailable/onDOMReady events need help when Event is
* loaded dynamically
* @method _pushEvents
* @param {Function} optional function reference
* @private
*/
_pushEvents: function(ref) {
var r = ref || YAHOO;
if (r.util && r.util.Event) {
r.util.Event._load();
}
},
/**
* Applies filter
* method _filter
* @return {string} the filtered string
* @private
*/
_filter: function(str) {
var f = this.filter;
return (f) ? str.replace(new RegExp(f.searchExp, 'g'), f.replaceStr) : str;
},
/**
* Generates the full url for a module
* method _url
* @param path {string} the path fragment
* @return {string} the full url
* @private
*/
_url: function(path) {
return this._filter((this.base || "") + path);
}
};
})();
YAHOO.register("yuiloader", YAHOO.util.YUILoader, {version: "2.8.0r4", build: "2449"});