/*
Copyright (c) 2010, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.com/yui/license.html
version: 3.3.0
build: 3167
*/
/**
* The YUI module contains the components required for building the YUI seed
* file. This includes the script loading mechanism, a simple queue, and
* the core utilities for the library.
* @module yui
* @submodule yui-base
*/
if (typeof YUI != 'undefined') {
YUI._YUI = YUI;
}
/**
* The YUI global namespace object. If YUI is already defined, the
* existing YUI object will not be overwritten so that defined
* namespaces are preserved. It is the constructor for the object
* the end user interacts with. As indicated below, each instance
* has full custom event support, but only if the event system
* is available. This is a self-instantiable factory function. You
* can invoke it directly like this:
*
* YUI().use('*', function(Y) {
* // ready
* });
*
* But it also works like this:
*
* var Y = YUI();
*
* @class YUI
* @constructor
* @global
* @uses EventTarget
* @param o* {object} 0..n optional configuration objects. these values
* are store in Y.config. See config for the list of supported
* properties.
*/
/*global YUI*/
/*global YUI_config*/
var YUI = function() {
var i = 0,
Y = this,
args = arguments,
l = args.length,
instanceOf = function(o, type) {
return (o && o.hasOwnProperty && (o instanceof type));
},
gconf = (typeof YUI_config !== 'undefined') && YUI_config;
if (!(instanceOf(Y, YUI))) {
Y = new YUI();
} else {
// set up the core environment
Y._init();
// YUI.GlobalConfig is a master configuration that might span
// multiple contexts in a non-browser environment. It is applied
// first to all instances in all contexts.
if (YUI.GlobalConfig) {
Y.applyConfig(YUI.GlobalConfig);
}
// YUI_Config is a page-level config. It is applied to all
// instances created on the page. This is applied after
// YUI.GlobalConfig, and before the instance level configuration
// objects.
if (gconf) {
Y.applyConfig(gconf);
}
// bind the specified additional modules for this instance
if (!l) {
Y._setup();
}
}
if (l) {
// Each instance can accept one or more configuration objects.
// These are applied after YUI.GlobalConfig and YUI_Config,
// overriding values set in those config files if there is a '
// matching property.
for (; i < l; i++) {
Y.applyConfig(args[i]);
}
Y._setup();
}
Y.instanceOf = instanceOf;
return Y;
};
(function() {
var proto, prop,
VERSION = '3.3.0',
PERIOD = '.',
BASE = 'http://yui.yahooapis.com/',
DOC_LABEL = 'yui3-js-enabled',
NOOP = function() {},
SLICE = Array.prototype.slice,
APPLY_TO_AUTH = { 'io.xdrReady': 1, // the functions applyTo
'io.xdrResponse': 1, // can call. this should
'SWF.eventHandler': 1 }, // be done at build time
hasWin = (typeof window != 'undefined'),
win = (hasWin) ? window : null,
doc = (hasWin) ? win.document : null,
docEl = doc && doc.documentElement,
docClass = docEl && docEl.className,
instances = {},
time = new Date().getTime(),
add = function(el, type, fn, capture) {
if (el && el.addEventListener) {
el.addEventListener(type, fn, capture);
} else if (el && el.attachEvent) {
el.attachEvent('on' + type, fn);
}
},
remove = function(el, type, fn, capture) {
if (el && el.removeEventListener) {
// this can throw an uncaught exception in FF
try {
el.removeEventListener(type, fn, capture);
} catch (ex) {}
} else if (el && el.detachEvent) {
el.detachEvent('on' + type, fn);
}
},
handleLoad = function() {
YUI.Env.windowLoaded = true;
YUI.Env.DOMReady = true;
if (hasWin) {
remove(window, 'load', handleLoad);
}
},
getLoader = function(Y, o) {
var loader = Y.Env._loader;
if (loader) {
loader.ignoreRegistered = false;
loader.onEnd = null;
loader.data = null;
loader.required = [];
loader.loadType = null;
} else {
loader = new Y.Loader(Y.config);
Y.Env._loader = loader;
}
return loader;
},
clobber = function(r, s) {
for (var i in s) {
if (s.hasOwnProperty(i)) {
r[i] = s[i];
}
}
},
ALREADY_DONE = { success: true };
// Stamp the documentElement (HTML) with a class of "yui-loaded" to
// enable styles that need to key off of JS being enabled.
if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
if (docClass) {
docClass += ' ';
}
docClass += DOC_LABEL;
docEl.className = docClass;
}
if (VERSION.indexOf('@') > -1) {
VERSION = '3.2.0'; // dev time hack for cdn test
}
proto = {
/**
* Applies a new configuration object to the YUI instance config.
* This will merge new group/module definitions, and will also
* update the loader cache if necessary. Updating Y.config directly
* will not update the cache.
* @method applyConfig
* @param {object} the configuration object.
* @since 3.2.0
*/
applyConfig: function(o) {
o = o || NOOP;
var attr,
name,
// detail,
config = this.config,
mods = config.modules,
groups = config.groups,
rls = config.rls,
loader = this.Env._loader;
for (name in o) {
if (o.hasOwnProperty(name)) {
attr = o[name];
if (mods && name == 'modules') {
clobber(mods, attr);
} else if (groups && name == 'groups') {
clobber(groups, attr);
} else if (rls && name == 'rls') {
clobber(rls, attr);
} else if (name == 'win') {
config[name] = attr.contentWindow || attr;
config.doc = config[name].document;
} else if (name == '_yuid') {
// preserve the guid
} else {
config[name] = attr;
}
}
}
if (loader) {
loader._config(o);
}
},
_config: function(o) {
this.applyConfig(o);
},
/**
* Initialize this YUI instance
* @private
*/
_init: function() {
var filter,
Y = this,
G_ENV = YUI.Env,
Env = Y.Env,
prop;
/**
* The version number of the YUI instance.
* @property version
* @type string
*/
Y.version = VERSION;
if (!Env) {
Y.Env = {
mods: {}, // flat module map
versions: {}, // version module map
base: BASE,
cdn: BASE + VERSION + '/build/',
// bootstrapped: false,
_idx: 0,
_used: {},
_attached: {},
_yidx: 0,
_uidx: 0,
_guidp: 'y',
_loaded: {},
serviced: {},
getBase: G_ENV && G_ENV.getBase ||
function(srcPattern, comboPattern) {
var b, nodes, i, src, match;
// get from querystring
nodes = (doc && doc.getElementsByTagName('script')) || [];
for (i = 0; i < nodes.length; i = i + 1) {
src = nodes[i].src;
if (src) {
match = src.match(srcPattern);
b = match && match[1];
if (b) {
// this is to set up the path to the loader. The file
// filter for loader should match the yui include.
filter = match[2];
if (filter) {
match = filter.indexOf('js');
if (match > -1) {
filter = filter.substr(0, match);
}
}
// extract correct path for mixed combo urls
// http://yuilibrary.com/projects/yui3/ticket/2528423
match = src.match(comboPattern);
if (match && match[3]) {
b = match[1] + match[3];
}
break;
}
}
}
// use CDN default
return b || Env.cdn;
}
};
Env = Y.Env;
Env._loaded[VERSION] = {};
if (G_ENV && Y !== YUI) {
Env._yidx = ++G_ENV._yidx;
Env._guidp = ('yui_' + VERSION + '_' +
Env._yidx + '_' + time).replace(/\./g, '_');
} else if (YUI._YUI) {
G_ENV = YUI._YUI.Env;
Env._yidx += G_ENV._yidx;
Env._uidx += G_ENV._uidx;
for (prop in G_ENV) {
if (!(prop in Env)) {
Env[prop] = G_ENV[prop];
}
}
delete YUI._YUI;
}
Y.id = Y.stamp(Y);
instances[Y.id] = Y;
}
Y.constructor = YUI;
// configuration defaults
Y.config = Y.config || {
win: win,
doc: doc,
debug: true,
useBrowserConsole: true,
throwFail: true,
bootstrap: true,
cacheUse: true,
fetchCSS: true
};
Y.config.base = YUI.config.base ||
Y.Env.getBase(/^(.*)yui\/yui([\.\-].*)js(\?.*)?$/,
/^(.*\?)(.*\&)(.*)yui\/yui[\.\-].*js(\?.*)?$/);
if (!filter || (!('-min.-debug.').indexOf(filter))) {
filter = '-min.';
}
Y.config.loaderPath = YUI.config.loaderPath ||
'loader/loader' + (filter || '-min.') + 'js';
},
/**
* Finishes the instance setup. Attaches whatever modules were defined
* when the yui modules was registered.
* @method _setup
* @private
*/
_setup: function(o) {
var i, Y = this,
core = [],
mods = YUI.Env.mods,
extras = Y.config.core || ['get',
'rls',
'intl-base',
'loader',
'yui-log',
'yui-later',
'yui-throttle'];
for (i = 0; i < extras.length; i++) {
if (mods[extras[i]]) {
core.push(extras[i]);
}
}
Y._attach(['yui-base']);
Y._attach(core);
},
/**
* Executes a method on a YUI instance with
* the specified id if the specified method is whitelisted.
* @method applyTo
* @param id {string} the YUI instance id.
* @param method {string} the name of the method to exectute.
* Ex: 'Object.keys'.
* @param args {Array} the arguments to apply to the method.
* @return {object} the return value from the applied method or null.
*/
applyTo: function(id, method, args) {
if (!(method in APPLY_TO_AUTH)) {
this.log(method + ': applyTo not allowed', 'warn', 'yui');
return null;
}
var instance = instances[id], nest, m, i;
if (instance) {
nest = method.split('.');
m = instance;
for (i = 0; i < nest.length; i = i + 1) {
m = m[nest[i]];
if (!m) {
this.log('applyTo not found: ' + method, 'warn', 'yui');
}
}
return m.apply(instance, args);
}
return null;
},
/**
* Registers a module with the YUI global. The easiest way to create a
* first-class YUI module is to use the YUI component build tool.
*
* http://yuilibrary.com/projects/builder
*
* The build system will produce the YUI.add wrapper for you module, along
* with any configuration info required for the module.
* @method add
* @param name {string} module name.
* @param fn {Function} entry point into the module that
* is used to bind module to the YUI instance.
* @param version {string} version string.
* @param details {object} optional config data:
* requires: features that must be present before this module can be
* attached.
* optional: optional features that should be present if loadOptional
* is defined. Note: modules are not often loaded this way in YUI 3,
* but this field is still useful to inform the user that certain
* features in the component will require additional dependencies.
* use: features that are included within this module which need to
* be attached automatically when this module is attached. This
* supports the YUI 3 rollup system -- a module with submodules
* defined will need to have the submodules listed in the 'use'
* config. The YUI component build tool does this for you.
* @return {YUI} the YUI instance.
*
*/
add: function(name, fn, version, details) {
details = details || {};
var env = YUI.Env,
mod = {
name: name,
fn: fn,
version: version,
details: details
},
loader,
i, versions = env.versions;
env.mods[name] = mod;
versions[version] = versions[version] || {};
versions[version][name] = mod;
for (i in instances) {
if (instances.hasOwnProperty(i)) {
loader = instances[i].Env._loader;
if (loader) {
if (!loader.moduleInfo[name]) {
loader.addModule(details, name);
}
}
}
}
return this;
},
/**
* Executes the function associated with each required
* module, binding the module to the YUI instance.
* @method _attach
* @private
*/
_attach: function(r, fromLoader) {
var i, name, mod, details, req, use, after,
mods = YUI.Env.mods,
Y = this, j,
done = Y.Env._attached,
len = r.length, loader;
for (i = 0; i < len; i++) {
if (!done[r[i]]) {
name = r[i];
mod = mods[name];
if (!mod) {
loader = Y.Env._loader;
if (!loader || !loader.moduleInfo[name]) {
Y.message('NOT loaded: ' + name, 'warn', 'yui');
}
} else {
done[name] = true;
details = mod.details;
req = details.requires;
use = details.use;
after = details.after;
if (req) {
for (j = 0; j < req.length; j++) {
if (!done[req[j]]) {
if (!Y._attach(req)) {
return false;
}
break;
}
}
}
if (after) {
for (j = 0; j < after.length; j++) {
if (!done[after[j]]) {
if (!Y._attach(after)) {
return false;
}
break;
}
}
}
if (use) {
for (j = 0; j < use.length; j++) {
if (!done[use[j]]) {
if (!Y._attach(use)) {
return false;
}
break;
}
}
}
if (mod.fn) {
try {
mod.fn(Y, name);
} catch (e) {
Y.error('Attach error: ' + name, e, name);
return false;
}
}
}
}
}
return true;
},
/**
* Attaches one or more modules to the YUI instance. When this
* is executed, the requirements are analyzed, and one of
* several things can happen:
*
* - All requirements are available on the page -- The modules
* are attached to the instance. If supplied, the use callback
* is executed synchronously.
*
* - Modules are missing, the Get utility is not available OR
* the 'bootstrap' config is false -- A warning is issued about
* the missing modules and all available modules are attached.
*
* - Modules are missing, the Loader is not available but the Get
* utility is and boostrap is not false -- The loader is bootstrapped
* before doing the following....
*
* - Modules are missing and the Loader is available -- The loader
* expands the dependency tree and fetches missing modules. When
* the loader is finshed the callback supplied to use is executed
* asynchronously.
*
* @param modules* {string} 1-n modules to bind (uses arguments array).
* @param *callback {function} callback function executed when
* the instance has the required functionality. If included, it
* must be the last parameter.
*
* // loads and attaches drag and drop and its dependencies
* YUI().use('dd', function(Y) {});
* // attaches all modules that are available on the page
* YUI().use('*', function(Y) {});
* // intrinsic YUI gallery support (since 3.1.0)
* YUI().use('gallery-yql', function(Y) {});
* // intrinsic YUI 2in3 support (since 3.1.0)
* YUI().use('yui2-datatable', function(Y) {});.
*
*
* @return {YUI} the YUI instance.
*/
use: function() {
var args = SLICE.call(arguments, 0),
callback = args[args.length - 1],
Y = this,
key;
// The last argument supplied to use can be a load complete callback
if (Y.Lang.isFunction(callback)) {
args.pop();
} else {
callback = null;
}
if (Y._loading) {
Y._useQueue = Y._useQueue || new Y.Queue();
Y._useQueue.add([args, callback]);
} else {
key = args.join();
if (Y.config.cacheUse && Y.Env.serviced[key]) {
Y._notify(callback, ALREADY_DONE, args);
} else {
Y._use(args, function(Y, response) {
if (Y.config.cacheUse) {
Y.Env.serviced[key] = true;
}
Y._notify(callback, response, args);
});
}
}
return Y;
},
_notify: function(callback, response, args) {
if (!response.success && this.config.loadErrorFn) {
this.config.loadErrorFn.call(this, this, callback, response, args);
} else if (callback) {
try {
callback(this, response);
} catch (e) {
this.error('use callback error', e, args);
}
}
},
_use: function(args, callback) {
if (!this.Array) {
this._attach(['yui-base']);
}
var len, loader, handleBoot,
Y = this,
G_ENV = YUI.Env,
mods = G_ENV.mods,
Env = Y.Env,
used = Env._used,
queue = G_ENV._loaderQueue,
firstArg = args[0],
YArray = Y.Array,
config = Y.config,
boot = config.bootstrap,
missing = [],
r = [],
ret = true,
fetchCSS = config.fetchCSS,
process = function(names, skip) {
if (!names.length) {
return;
}
YArray.each(names, function(name) {
// add this module to full list of things to attach
if (!skip) {
r.push(name);
}
// only attach a module once
if (used[name]) {
return;
}
var m = mods[name], req, use;
if (m) {
used[name] = true;
req = m.details.requires;
use = m.details.use;
} else {
// CSS files don't register themselves, see if it has
// been loaded
if (!G_ENV._loaded[VERSION][name]) {
missing.push(name);
} else {
used[name] = true; // probably css
}
}
// make sure requirements are attached
if (req && req.length) {
process(req);
}
// make sure we grab the submodule dependencies too
if (use && use.length) {
process(use, 1);
}
});
},
handleLoader = function(fromLoader) {
var response = fromLoader || {
success: true,
msg: 'not dynamic'
},
redo, origMissing,
ret = true,
data = response.data;
Y._loading = false;
if (data) {
origMissing = missing;
missing = [];
r = [];
process(data);
redo = missing.length;
if (redo) {
if (missing.sort().join() ==
origMissing.sort().join()) {
redo = false;
}
}
}
if (redo && data) {
Y._loading = false;
Y._use(args, function() {
if (Y._attach(data)) {
Y._notify(callback, response, data);
}
});
} else {
if (data) {
ret = Y._attach(data);
}
if (ret) {
Y._notify(callback, response, args);
}
}
if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
Y._use.apply(Y, Y._useQueue.next());
}
};
// YUI().use('*'); // bind everything available
if (firstArg === '*') {
ret = Y._attach(Y.Object.keys(mods));
if (ret) {
handleLoader();
}
return Y;
}
// use loader to expand dependencies and sort the
// requirements if it is available.
if (boot && Y.Loader && args.length) {
loader = getLoader(Y);
loader.require(args);
loader.ignoreRegistered = true;
loader.calculate(null, (fetchCSS) ? null : 'js');
args = loader.sorted;
}
// process each requirement and any additional requirements
// the module metadata specifies
process(args);
len = missing.length;
if (len) {
missing = Y.Object.keys(YArray.hash(missing));
len = missing.length;
}
// dynamic load
if (boot && len && Y.Loader) {
Y._loading = true;
loader = getLoader(Y);
loader.onEnd = handleLoader;
loader.context = Y;
loader.data = args;
loader.ignoreRegistered = false;
loader.require(args);
loader.insert(null, (fetchCSS) ? null : 'js');
// loader.partial(missing, (fetchCSS) ? null : 'js');
} else if (len && Y.config.use_rls) {
// server side loader service
Y.Get.script(Y._rls(args), {
onEnd: function(o) {
handleLoader(o);
},
data: args
});
} else if (boot && len && Y.Get && !Env.bootstrapped) {
Y._loading = true;
handleBoot = function() {
Y._loading = false;
queue.running = false;
Env.bootstrapped = true;
if (Y._attach(['loader'])) {
Y._use(args, callback);
}
};
if (G_ENV._bootstrapping) {
queue.add(handleBoot);
} else {
G_ENV._bootstrapping = true;
Y.Get.script(config.base + config.loaderPath, {
onEnd: handleBoot
});
}
} else {
ret = Y._attach(args);
if (ret) {
handleLoader();
}
}
return Y;
},
/**
* Returns the namespace specified and creates it if it doesn't exist
*
* YUI.namespace("property.package"); * YUI.namespace("YAHOO.property.package"); ** Either of the above would create YUI.property, then * YUI.property.package (YAHOO is scrubbed out, this is * to remain compatible with YUI2) * * Be careful when naming packages. Reserved words may work in some browsers * and not others. For instance, the following will fail in Safari: *
* YUI.namespace("really.long.nested.namespace"); ** This fails because "long" is a future reserved word in ECMAScript * * @method namespace * @param {string*} arguments 1-n namespaces to create. * @return {object} A reference to the last namespace object created. */ namespace: function() { var a = arguments, o = this, i = 0, j, d, arg; for (; i < a.length; i++) { // d = ('' + a[i]).split('.'); arg = a[i]; if (arg.indexOf(PERIOD)) { d = arg.split(PERIOD); for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) { o[d[j]] = o[d[j]] || {}; o = o[d[j]]; } } else { o[arg] = o[arg] || {}; } } return o; }, // this is replaced if the log module is included log: NOOP, message: NOOP, /** * Report an error. The reporting mechanism is controled by * the 'throwFail' configuration attribute. If throwFail is * not specified, the message is written to the Logger, otherwise * a JS error is thrown * @method error * @param msg {string} the error message. * @param e {Error|string} Optional JS error that was caught, or an error string. * @param data Optional additional info * and throwFail is specified, this error will be re-thrown. * @return {YUI} this YUI instance. */ error: function(msg, e, data) { var Y = this, ret; if (Y.config.errorFn) { ret = Y.config.errorFn.apply(Y, arguments); } if (Y.config.throwFail && !ret) { throw (e || new Error(msg)); } else { Y.message(msg, 'error'); // don't scrub this one } return Y; }, /** * Generate an id that is unique among all YUI instances * @method guid * @param pre {string} optional guid prefix. * @return {string} the guid. */ guid: function(pre) { var id = this.Env._guidp + (++this.Env._uidx); return (pre) ? (pre + id) : id; }, /** * Returns a guid associated with an object. If the object * does not have one, a new one is created unless readOnly * is specified. * @method stamp * @param o The object to stamp. * @param readOnly {boolean} if true, a valid guid will only * be returned if the object has one assigned to it. * @return {string} The object's guid or null. */ stamp: function(o, readOnly) { var uid; if (!o) { return o; } // IE generates its own unique ID for dom nodes // The uniqueID property of a document node returns a new ID if (o.uniqueID && o.nodeType && o.nodeType !== 9) { uid = o.uniqueID; } else { uid = (typeof o === 'string') ? o : o._yuid; } if (!uid) { uid = this.guid(); if (!readOnly) { try { o._yuid = uid; } catch (e) { uid = null; } } } return uid; }, /** * Destroys the YUI instance * @method destroy * @since 3.3.0 */ destroy: function() { var Y = this; if (Y.Event) { Y.Event._unload(); } delete instances[Y.id]; delete Y.Env; delete Y.config; } /** * instanceof check for objects that works around * memory leak in IE when the item tested is * window/document * @method instanceOf * @since 3.3.0 */ }; YUI.prototype = proto; // inheritance utilities are not available yet for (prop in proto) { if (proto.hasOwnProperty(prop)) { YUI[prop] = proto[prop]; } } // set up the environment YUI._init(); if (hasWin) { // add a window load event at load time so we can capture // the case where it fires before dynamic loading is // complete. add(window, 'load', handleLoad); } else { handleLoad(); } YUI.Env.add = add; YUI.Env.remove = remove; /*global exports*/ // Support the CommonJS method for exporting our single global if (typeof exports == 'object') { exports.YUI = YUI; } }()); /** * The config object contains all of the configuration options for * the YUI instance. This object is supplied by the implementer * when instantiating a YUI instance. Some properties have default * values if they are not supplied by the implementer. This should * not be updated directly because some values are cached. Use * applyConfig() to update the config object on a YUI instance that * has already been configured. * * @class config * @static */ /** * Allows the YUI seed file to fetch the loader component and library * metadata to dynamically load additional dependencies. * * @property bootstrap * @type boolean * @default true */ /** * Log to the browser console if debug is on and the browser has a * supported console. * * @property useBrowserConsole * @type boolean * @default true */ /** * A hash of log sources that should be logged. If specified, only * log messages from these sources will be logged. * * @property logInclude * @type object */ /** * A hash of log sources that should be not be logged. If specified, * all sources are logged if not on this list. * * @property logExclude * @type object */ /** * Set to true if the yui seed file was dynamically loaded in * order to bootstrap components relying on the window load event * and the 'domready' custom event. * * @property injected * @type boolean * @default false */ /** * If throwFail is set, Y.error will generate or re-throw a JS Error. * Otherwise the failure is logged. * * @property throwFail * @type boolean * @default true */ /** * The window/frame that this instance should operate in. * * @property win * @type Window * @default the window hosting YUI */ /** * The document associated with the 'win' configuration. * * @property doc * @type Document * @default the document hosting YUI */ /** * A list of modules that defines the YUI core (overrides the default). * * @property core * @type string[] */ /** * A list of languages in order of preference. This list is matched against * the list of available languages in modules that the YUI instance uses to * determine the best possible localization of language sensitive modules. * Languages are represented using BCP 47 language tags, such as "en-GB" for * English as used in the United Kingdom, or "zh-Hans-CN" for simplified * Chinese as used in China. The list can be provided as a comma-separated * list or as an array. * * @property lang * @type string|string[] */ /** * The default date format * @property dateFormat * @type string * @deprecated use configuration in DataType.Date.format() instead. */ /** * The default locale * @property locale * @type string * @deprecated use config.lang instead. */ /** * The default interval when polling in milliseconds. * @property pollInterval * @type int * @default 20 */ /** * The number of dynamic nodes to insert by default before * automatically removing them. This applies to script nodes * because remove the node will not make the evaluated script * unavailable. Dynamic CSS is not auto purged, because removing * a linked style sheet will also remove the style definitions. * @property purgethreshold * @type int * @default 20 */ /** * The default interval when polling in milliseconds. * @property windowResizeDelay * @type int * @default 40 */ /** * Base directory for dynamic loading * @property base * @type string */ /* * The secure base dir (not implemented) * For dynamic loading. * @property secureBase * @type string */ /** * The YUI combo service base dir. Ex: http://yui.yahooapis.com/combo? * For dynamic loading. * @property comboBase * @type string */ /** * The root path to prepend to module path for the combo service. * Ex: 3.0.0b1/build/ * For dynamic loading. * @property root * @type string */ /** * 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: *
* myFilter: { * 'searchExp': "-min\\.js", * 'replaceStr': "-debug.js" * } ** * For dynamic loading. * * @property filter * @type string|object */ /** * The 'skin' config let's you configure application level skin * customizations. It contains the following attributes which * can be specified to override the defaults: * * // 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. * base: 'assets/skins/', * * // 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: { * slider: ['capsule', 'round'] * } * * For dynamic loading. * * @property skin */ /** * Hash of per-component filter specification. If specified for a given * component, this overrides the filter config. * * For dynamic loading. * * @property filters */ /** * Use the YUI combo service to reduce the number of http connections * required to load your dependencies. Turning this off will * disable combo handling for YUI and all module groups configured * with a combo service. * * For dynamic loading. * * @property combine * @type boolean * @default true if 'base' is not supplied, false if it is. */ /** * A list of modules that should never be dynamically loaded * * @property ignore * @type string[] */ /** * A list of modules that should always be loaded when required, even if already * present on the page. * * @property force * @type string[] */ /** * Node or id for a node that should be used as the insertion point for new * nodes. For dynamic loading. * * @property insertBefore * @type string */ /** * Object literal containing attributes to add to dynamically loaded script * nodes. * @property jsAttributes * @type string */ /** * Object literal containing attributes to add to dynamically loaded link * nodes. * @property cssAttributes * @type string */ /** * Number of milliseconds before a timeout occurs when dynamically * loading nodes. If not set, there is no timeout. * @property timeout * @type int */ /** * Callback for the 'CSSComplete' event. When dynamically loading YUI * components with CSS, this property fires when the CSS is finished * loading but script loading is still ongoing. This provides an * opportunity to enhance the presentation of a loading page a little * bit before the entire loading process is done. * * @property onCSS * @type function */ /** * A hash of module definitions to add to the list of YUI components. * These components can then be dynamically loaded side by side with * YUI via the use() method. This is a hash, the key is the module * name, and the value is an object literal specifying the metdata * for the module. * See Loader.addModule for the supported module * metadata fields. Also @see groups, which provides a way to * configure the base and combo spec for a set of modules. *
* modules: {
* mymod1: {
* requires: ['node'],
* fullpath: 'http://myserver.mydomain.com/mymod1/mymod1.js'
* },
* mymod2: {
* requires: ['mymod1'],
* fullpath: 'http://myserver.mydomain.com/mymod2/mymod2.js'
* }
* }
*
*
* @property modules
* @type object
*/
/**
* A hash of module group definitions. It for each group you
* can specify a list of modules and the base path and
* combo spec to use when dynamically loading the modules. @see
* @see modules for the details about the modules part of the
* group definition.
*
* groups: {
* yui2: {
* // specify whether or not this group has a combo service
* combine: true,
*
* // the base path for non-combo paths
* base: 'http://yui.yahooapis.com/2.8.0r4/build/',
*
* // the path to the combo service
* comboBase: 'http://yui.yahooapis.com/combo?',
*
* // a fragment to prepend to the path attribute when
* // when building combo urls
* root: '2.8.0r4/build/',
*
* // the module definitions
* modules: {
* yui2_yde: {
* path: "yahoo-dom-event/yahoo-dom-event.js"
* },
* yui2_anim: {
* path: "animation/animation.js",
* requires: ['yui2_yde']
* }
* }
* }
* }
*
* @property modules
* @type object
*/
/**
* The loader 'path' attribute to the loader itself. This is combined
* with the 'base' attribute to dynamically load the loader component
* when boostrapping with the get utility alone.
*
* @property loaderPath
* @type string
* @default loader/loader-min.js
*/
/**
* Specifies whether or not YUI().use(...) will attempt to load CSS
* resources at all. Any truthy value will cause CSS dependencies
* to load when fetching script. The special value 'force' will
* cause CSS dependencies to be loaded even if no script is needed.
*
* @property fetchCSS
* @type boolean|string
* @default true
*/
/**
* The default gallery version to build gallery module urls
* @property gallery
* @type string
* @since 3.1.0
*/
/**
* The default YUI 2 version to build yui2 module urls. This is for
* intrinsic YUI 2 support via the 2in3 project. Also @see the '2in3'
* config for pulling different revisions of the wrapped YUI 2
* modules.
* @since 3.1.0
* @property yui2
* @type string
* @default 2.8.1
*/
/**
* The 2in3 project is a deployment of the various versions of YUI 2
* deployed as first-class YUI 3 modules. Eventually, the wrapper
* for the modules will change (but the underlying YUI 2 code will
* be the same), and you can select a particular version of
* the wrapper modules via this config.
* @since 3.1.0
* @property 2in3
* @type string
* @default 1
*/
/**
* Alternative console log function for use in environments without
* a supported native console. The function is executed in the
* YUI instance context.
* @since 3.1.0
* @property logFn
* @type Function
*/
/**
* A callback to execute when Y.error is called. It receives the
* error message and an javascript error object if Y.error was
* executed because a javascript error was caught. The function
* is executed in the YUI instance context.
*
* @since 3.2.0
* @property errorFn
* @type Function
*/
/**
* A callback to execute when the loader fails to load one or
* more resource. This could be because of a script load
* failure. It can also fail if a javascript module fails
* to register itself, but only when the 'requireRegistration'
* is true. If this function is defined, the use() callback will
* only be called when the loader succeeds, otherwise it always
* executes unless there was a javascript error when attaching
* a module.
*
* @since 3.3.0
* @property loadErrorFn
* @type Function
*/
/**
* When set to true, the YUI loader will expect that all modules
* it is responsible for loading will be first-class YUI modules
* that register themselves with the YUI global. If this is
* set to true, loader will fail if the module registration fails
* to happen after the script is loaded.
*
* @since 3.3.0
* @property requireRegistration
* @type boolean
* @default false
*/
/**
* Cache serviced use() requests.
* @since 3.3.0
* @property cacheUse
* @type boolean
* @default true
*/
/**
* The parameter defaults for the remote loader service.
* Requires the rls submodule. The properties that are
* supported:
* * m: comma separated list of module requirements. This * must be the param name even for custom implemetations. * v: the version of YUI to load. Defaults to the version * of YUI that is being used. * gv: the version of the gallery to load (@see the gallery config) * env: comma separated list of modules already on the page. * this must be the param name even for custom implemetations. * lang: the languages supported on the page (@see the lang config) * '2in3v': the version of the 2in3 wrapper to use (@see the 2in3 config). * '2v': the version of yui2 to use in the yui 2in3 wrappers * (@see the yui2 config) * filt: a filter def to apply to the urls (@see the filter config). * filts: a list of custom filters to apply per module * (@see the filters config). * tests: this is a map of conditional module test function id keys * with the values of 1 if the test passes, 0 if not. This must be * the name of the querystring param in custom templates. ** * @since 3.2.0 * @property rls */ /** * The base path to the remote loader service * * @since 3.2.0 * @property rls_base */ /** * The template to use for building the querystring portion * of the remote loader service url. The default is determined * by the rls config -- each property that has a value will be * represented. * * ex: m={m}&v={v}&env={env}&lang={lang}&filt={filt}&tests={tests} * * * @since 3.2.0 * @property rls_tmpl */ /** * Configure the instance to use a remote loader service instead of * the client loader. * * @since 3.2.0 * @property use_rls */ YUI.add('yui-base', function(Y) { /* * YUI stub * @module yui * @submodule yui-base */ /** * The YUI module contains the components required for building the YUI * seed file. This includes the script loading mechanism, a simple queue, * and the core utilities for the library. * @module yui * @submodule yui-base */ /** * Provides the language utilites and extensions used by the library * @class Lang * @static */ Y.Lang = Y.Lang || {}; var L = Y.Lang, ARRAY = 'array', BOOLEAN = 'boolean', DATE = 'date', ERROR = 'error', FUNCTION = 'function', NUMBER = 'number', NULL = 'null', OBJECT = 'object', REGEX = 'regexp', STRING = 'string', STRING_PROTO = String.prototype, TOSTRING = Object.prototype.toString, UNDEFINED = 'undefined', TYPES = { 'undefined' : UNDEFINED, 'number' : NUMBER, 'boolean' : BOOLEAN, 'string' : STRING, '[object Function]' : FUNCTION, '[object RegExp]' : REGEX, '[object Array]' : ARRAY, '[object Date]' : DATE, '[object Error]' : ERROR }, TRIMREGEX = /^\s+|\s+$/g, EMPTYSTRING = '', SUBREGEX = /\{\s*([^\|\}]+?)\s*(?:\|([^\}]*))?\s*\}/g; /** * Determines whether or not the provided item is an array. * Returns false for array-like collections such as the * function arguments collection or HTMLElement collection * will return false. Use
Y.Array.test
if you
* want to test for an array-like collection.
* @method isArray
* @static
* @param o The object to test.
* @return {boolean} true if o is an array.
*/
// L.isArray = Array.isArray || function(o) {
// return L.type(o) === ARRAY;
// };
L.isArray = function(o) {
return L.type(o) === ARRAY;
};
/**
* Determines whether or not the provided item is a boolean.
* @method isBoolean
* @static
* @param o The object to test.
* @return {boolean} true if o is a boolean.
*/
L.isBoolean = function(o) {
return typeof o === BOOLEAN;
};
/**
* * Determines whether or not the provided item is a function. * Note: Internet Explorer thinks certain functions are objects: *
* ** var obj = document.createElement("object"); * Y.Lang.isFunction(obj.getAttribute) // reports false in IE * * var input = document.createElement("input"); // append to body * Y.Lang.isFunction(input.focus) // reports false in IE ** *
* You will have to implement additional tests if these functions * matter to you. *
* * @method isFunction * @static * @param o The object to test. * @return {boolean} true if o is a function. */ L.isFunction = function(o) { return L.type(o) === FUNCTION; }; /** * Determines whether or not the supplied item is a date instance. * @method isDate * @static * @param o The object to test. * @return {boolean} true if o is a date. */ L.isDate = function(o) { // return o instanceof Date; return L.type(o) === DATE && o.toString() !== 'Invalid Date' && !isNaN(o); }; /** * Determines whether or not the provided item is null. * @method isNull * @static * @param o The object to test. * @return {boolean} true if o is null. */ L.isNull = function(o) { return o === null; }; /** * Determines whether or not the provided item is a legal number. * @method isNumber * @static * @param o The object to test. * @return {boolean} true if o is a number. */ L.isNumber = function(o) { return typeof o === NUMBER && isFinite(o); }; /** * Determines whether or not the provided item is of type object * or function. Note that arrays are also objects, so *Y.Lang.isObject([]) === true
.
* @method isObject
* @static
* @param o The object to test.
* @param failfn {boolean} fail if the input is a function.
* @return {boolean} true if o is an object.
*/
L.isObject = function(o, failfn) {
var t = typeof o;
return (o && (t === OBJECT ||
(!failfn && (t === FUNCTION || L.isFunction(o))))) || false;
};
/**
* Determines whether or not the provided item is a string.
* @method isString
* @static
* @param o The object to test.
* @return {boolean} true if o is a string.
*/
L.isString = function(o) {
return typeof o === STRING;
};
/**
* Determines whether or not the provided item is undefined.
* @method isUndefined
* @static
* @param o The object to test.
* @return {boolean} true if o is undefined.
*/
L.isUndefined = function(o) {
return typeof o === UNDEFINED;
};
/**
* Returns a string without any leading or trailing whitespace. If
* the input is not a string, the input will be returned untouched.
* @method trim
* @static
* @param s {string} the string to trim.
* @return {string} the trimmed string.
*/
L.trim = STRING_PROTO.trim ? function(s) {
return (s && s.trim) ? s.trim() : s;
} : function (s) {
try {
return s.replace(TRIMREGEX, EMPTYSTRING);
} catch (e) {
return s;
}
};
/**
* Returns a string without any leading whitespace.
* @method trimLeft
* @static
* @param s {string} the string to trim.
* @return {string} the trimmed string.
*/
L.trimLeft = STRING_PROTO.trimLeft ? function (s) {
return s.trimLeft();
} : function (s) {
return s.replace(/^\s+/, '');
};
/**
* Returns a string without any trailing whitespace.
* @method trimRight
* @static
* @param s {string} the string to trim.
* @return {string} the trimmed string.
*/
L.trimRight = STRING_PROTO.trimRight ? function (s) {
return s.trimRight();
} : function (s) {
return s.replace(/\s+$/, '');
};
/**
* 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
* @static
* @param o The item to test.
* @return {boolean} true if it is not null/undefined/NaN || false.
*/
L.isValue = function(o) {
var t = L.type(o);
switch (t) {
case NUMBER:
return isFinite(o);
case NULL:
case UNDEFINED:
return false;
default:
return !!(t);
}
};
/**
* * Returns a string representing the type of the item passed in. *
* ** Known issues: *
* *typeof HTMLElementCollection
returns function in Safari, but
* Y.type()
reports object, which could be a good thing --
* but it actually caused the logic in Y.Lang.isObject
to fail.
* Y.substitute
. Uses the same template
* structure as Y.substitute
, but doesn't support recursion,
* auto-object coersion, or formats.
* @method sub
* @param {string} s String to be modified.
* @param {object} o Object containing replacement values.
* @return {string} the substitute result.
* @static
* @since 3.2.0
*/
L.sub = function(s, o) {
return ((s.replace) ? s.replace(SUBREGEX, function(match, key) {
return (!L.isUndefined(o[key])) ? o[key] : match;
}) : s);
};
/**
* Returns the current time in milliseconds.
* @method now
* @return {int} the current date
* @since 3.3.0
*/
L.now = Date.now || function () {
return new Date().getTime();
};
/**
* The YUI module contains the components required for building the YUI seed
* file. This includes the script loading mechanism, a simple queue, and the
* core utilities for the library.
* @module yui
* @submodule yui-base
*/
var Native = Array.prototype, LENGTH = 'length',
/**
* Adds the following array utilities to the YUI instance. Additional
* array helpers can be found in the collection component.
* @class Array
*/
/**
* Y.Array(o) returns an array:
* - Arrays are return unmodified unless the start position is specified.
* - "Array-like" collections (@see Array.test) are converted to arrays
* - For everything else, a new array is created with the input as the sole
* item.
* - The start position is used if the input is or is like an array to return
* a subset of the collection.
*
* @todo this will not automatically convert elements that are also
* collections such as forms and selects. Passing true as the third
* param will force a conversion.
*
* @method ()
* @static
* @param {object} o the item to arrayify.
* @param {int} startIdx if an array or array-like, this is the start index.
* @param {boolean} arraylike if true, it forces the array-like fork. This
* can be used to avoid multiple Array.test calls.
* @return {Array} the resulting array.
*/
YArray = function(o, startIdx, arraylike) {
var t = (arraylike) ? 2 : YArray.test(o),
l, a, start = startIdx || 0;
if (t) {
// IE errors when trying to slice HTMLElement collections
try {
return Native.slice.call(o, start);
} catch (e) {
a = [];
l = o.length;
for (; start < l; start++) {
a.push(o[start]);
}
return a;
}
} else {
return [o];
}
};
Y.Array = YArray;
/**
* Evaluates the input to determine if it is an array, array-like, or
* something else. This is used to handle the arguments collection
* available within functions, and HTMLElement collections
*
* @method test
* @static
*
* @todo current implementation (intenionally) will not implicitly
* handle html elements that are array-like (forms, selects, etc).
*
* @param {object} o the object to test.
*
* @return {int} a number indicating the results:
* 0: Not an array or an array-like collection
* 1: A real array.
* 2: array-like collection.
*/
YArray.test = function(o) {
var r = 0;
if (Y.Lang.isObject(o)) {
if (Y.Lang.isArray(o)) {
r = 1;
} else {
try {
// indexed, but no tagName (element) or alert (window),
// or functions without apply/call (Safari
// HTMLElementCollection bug).
if ((LENGTH in o) && !o.tagName && !o.alert && !o.apply) {
r = 2;
}
} catch (e) {}
}
}
return r;
};
/**
* Executes the supplied function on each item in the array.
* @method each
* @param {Array} a the array to iterate.
* @param {Function} f the function to execute on each item. The
* function receives three arguments: the value, the index, the full array.
* @param {object} o Optional context object.
* @static
* @return {YUI} the YUI instance.
*/
YArray.each = (Native.forEach) ?
function(a, f, o) {
Native.forEach.call(a || [], f, o || Y);
return Y;
} :
function(a, f, o) {
var l = (a && a.length) || 0, i;
for (i = 0; i < l; i = i + 1) {
f.call(o || Y, a[i], i, a);
}
return Y;
};
/**
* Returns an object using the first array as keys, and
* the second as values. If the second array is not
* provided the value is set to true for each.
* @method hash
* @static
* @param {Array} k keyset.
* @param {Array} v optional valueset.
* @return {object} the hash.
*/
YArray.hash = function(k, v) {
var o = {}, l = k.length, vl = v && v.length, i;
for (i = 0; i < l; i = i + 1) {
o[k[i]] = (vl && vl > i) ? v[i] : true;
}
return o;
};
/**
* Returns the index of the first item in the array
* that contains the specified value, -1 if the
* value isn't found.
* @method indexOf
* @static
* @param {Array} a the array to search.
* @param {any} val the value to search for.
* @return {int} the index of the item that contains the value or -1.
*/
YArray.indexOf = (Native.indexOf) ?
function(a, val) {
return Native.indexOf.call(a, val);
} :
function(a, val) {
for (var i = 0; i < a.length; i = i + 1) {
if (a[i] === val) {
return i;
}
}
return -1;
};
/**
* Numeric sort convenience function.
* Y.ArrayAssert.itemsAreEqual([1,2,3], [3,1,2].sort(Y.Array.numericSort));
* @method numericSort
* @static
* @param {number} a a number.
* @param {number} b a number.
*/
YArray.numericSort = function(a, b) {
return (a - b);
};
/**
* Executes the supplied function on each item in the array.
* Returning true from the processing function will stop the
* processing of the remaining items.
* @method some
* @param {Array} a the array to iterate.
* @param {Function} f the function to execute on each item. The function
* receives three arguments: the value, the index, the full array.
* @param {object} o Optional context object.
* @static
* @return {boolean} true if the function returns true on
* any of the items in the array.
*/
YArray.some = (Native.some) ?
function(a, f, o) {
return Native.some.call(a, f, o);
} :
function(a, f, o) {
var l = a.length, i;
for (i = 0; i < l; i = i + 1) {
if (f.call(o, a[i], i, a)) {
return true;
}
}
return false;
};
/**
* The YUI module contains the components required for building the YUI
* seed file. This includes the script loading mechanism, a simple queue,
* and the core utilities for the library.
* @module yui
* @submodule yui-base
*/
/**
* A simple FIFO queue. Items are added to the Queue with add(1..n items) and
* removed using next().
*
* @class Queue
* @constructor
* @param {MIXED} item* 0..n items to seed the queue.
*/
function Queue() {
this._init();
this.add.apply(this, arguments);
}
Queue.prototype = {
/**
* Initialize the queue
*
* @method _init
* @protected
*/
_init: function() {
/**
* The collection of enqueued items
*
* @property _q
* @type Array
* @protected
*/
this._q = [];
},
/**
* Get the next item in the queue. FIFO support
*
* @method next
* @return {MIXED} the next item in the queue.
*/
next: function() {
return this._q.shift();
},
/**
* Get the last in the queue. LIFO support.
*
* @method last
* @return {MIXED} the last item in the queue.
*/
last: function() {
return this._q.pop();
},
/**
* Add 0..n items to the end of the queue.
*
* @method add
* @param {MIXED} item* 0..n items.
* @return {object} this queue.
*/
add: function() {
this._q.push.apply(this._q, arguments);
return this;
},
/**
* Returns the current number of queued items.
*
* @method size
* @return {Number} The size.
*/
size: function() {
return this._q.length;
}
};
Y.Queue = Queue;
YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
/**
* The YUI module contains the components required for building the YUI
* seed file. This includes the script loading mechanism, a simple queue,
* and the core utilities for the library.
* @module yui
* @submodule yui-base
*/
var CACHED_DELIMITER = '__',
/*
* 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 _iefix
* @for YUI
* @param {Function} r the object to receive the augmentation
* @param {Function} s the object that supplies the properties to augment
* @private
*/
_iefix = function(r, s) {
var fn = s.toString;
if (Y.Lang.isFunction(fn) && fn != Object.prototype.toString) {
r.toString = fn;
}
};
/**
* 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. Passing in a
* single object will create a shallow copy of it. For a deep
* copy, use clone.
* @method merge
* @for YUI
* @param arguments {Object*} the objects to merge.
* @return {object} the new merged object.
*/
Y.merge = function() {
var a = arguments, o = {}, i, l = a.length;
for (i = 0; i < l; i = i + 1) {
Y.mix(o, a[i], true);
}
return o;
};
/**
* Applies the supplier's properties to the receiver. By default
* all prototype and static propertes on the supplier are applied
* to the corresponding spot on the receiver. By default all
* properties are applied, and a property that is already on the
* reciever will not be overwritten. The default behavior can
* be modified by supplying the appropriate parameters.
*
* @todo add constants for the modes
*
* @method mix
* @param {Function} r the object to receive the augmentation.
* @param {Function} s the object that supplies the properties to augment.
* @param ov {boolean} if true, properties already on the receiver
* will be overwritten if found on the supplier.
* @param wl {string[]} a whitelist. If supplied, only properties in
* this list will be applied to the receiver.
* @param {int} mode what should be copies, and to where
* default(0): object to object
* 1: prototype to prototype (old augment)
* 2: prototype to prototype and object props (new augment)
* 3: prototype to object
* 4: object to prototype.
* @param merge {boolean/int} merge objects instead of overwriting/ignoring.
* A value of 2 will skip array merge
* Used by Y.aggregate.
* @return {object} the augmented object.
*/
Y.mix = function(r, s, ov, wl, mode, merge) {
if (!s || !r) {
return r || Y;
}
if (mode) {
switch (mode) {
case 1: // proto to proto
return Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
case 2: // object to object and proto to proto
Y.mix(r.prototype, s.prototype, ov, wl, 0, merge);
break; // pass through
case 3: // proto to static
return Y.mix(r, s.prototype, ov, wl, 0, merge);
case 4: // static to proto
return Y.mix(r.prototype, s, ov, wl, 0, merge);
default: // object to object is what happens below
}
}
// Maybe don't even need this wl && wl.length check anymore??
var i, l, p, type;
if (wl && wl.length) {
for (i = 0, l = wl.length; i < l; ++i) {
p = wl[i];
type = Y.Lang.type(r[p]);
if (s.hasOwnProperty(p)) {
if (merge && type == 'object') {
Y.mix(r[p], s[p]);
} else if (ov || !(p in r)) {
r[p] = s[p];
}
}
}
} else {
for (i in s) {
// if (s.hasOwnProperty(i) && !(i in FROZEN)) {
if (s.hasOwnProperty(i)) {
// check white list if it was supplied
// if the receiver has this property, it is an object,
// and merge is specified, merge the two objects.
if (merge && Y.Lang.isObject(r[i], true)) {
Y.mix(r[i], s[i], ov, wl, 0, true); // recursive
// otherwise apply the property only if overwrite
// is specified or the receiver doesn't have one.
} else if (ov || !(i in r)) {
r[i] = s[i];
}
// if merge is specified and the receiver is an array,
// append the array item
// } else if (arr) {
// r.push(s[i]);
// }
}
}
if (Y.UA.ie) {
_iefix(r, s);
}
}
return r;
};
/**
* Returns a wrapper for a function which caches the
* return value of that function, keyed off of the combined
* argument values.
* @method cached
* @param source {function} the function to memoize.
* @param cache an optional cache seed.
* @param refetch if supplied, this value is tested against the cached
* value. If the values are equal, the wrapped function is executed again.
* @return {Function} the wrapped function.
*/
Y.cached = function(source, cache, refetch) {
cache = cache || {};
return function(arg1) {
var k = (arguments.length > 1) ?
Array.prototype.join.call(arguments, CACHED_DELIMITER) : arg1;
if (!(k in cache) || (refetch && cache[k] == refetch)) {
cache[k] = source.apply(source, arguments);
}
return cache[k];
};
};
/**
* The YUI module contains the components required for building the YUI
* seed file. This includes the script loading mechanism, a simple queue,
* and the core utilities for the library.
* @module yui
* @submodule yui-base
*/
/**
* Adds the following Object utilities to the YUI instance
* @class Object
*/
/**
* Y.Object(o) returns a new object based upon the supplied object.
* @method ()
* @static
* @param o the supplier object.
* @return {Object} the new object.
*/
var F = function() {},
// O = Object.create || function(o) {
// F.prototype = o;
// return new F();
// },
O = function(o) {
F.prototype = o;
return new F();
},
owns = function(o, k) {
return o && o.hasOwnProperty && o.hasOwnProperty(k);
// return Object.prototype.hasOwnProperty.call(o, k);
},
UNDEF,
/**
* Extracts the keys, values, or size from an object
*
* @method _extract
* @param o the object.
* @param what what to extract (0: keys, 1: values, 2: size).
* @return {boolean|Array} the extracted info.
* @static
* @private
*/
_extract = function(o, what) {
var count = (what === 2), out = (count) ? 0 : [], i;
for (i in o) {
if (owns(o, i)) {
if (count) {
out++;
} else {
out.push((what) ? o[i] : i);
}
}
}
return out;
};
Y.Object = O;
/**
* Returns an array containing the object's keys
* @method keys
* @static
* @param o an object.
* @return {string[]} the keys.
*/
// O.keys = Object.keys || function(o) {
// return _extract(o);
// };
O.keys = function(o) {
return _extract(o);
};
/**
* Returns an array containing the object's values
* @method values
* @static
* @param o an object.
* @return {Array} the values.
*/
// O.values = Object.values || function(o) {
// return _extract(o, 1);
// };
O.values = function(o) {
return _extract(o, 1);
};
/**
* Returns the size of an object
* @method size
* @static
* @param o an object.
* @return {int} the size.
*/
O.size = Object.size || function(o) {
return _extract(o, 2);
};
/**
* Returns true if the object contains a given key
* @method hasKey
* @static
* @param o an object.
* @param k the key to query.
* @return {boolean} true if the object contains the key.
*/
O.hasKey = owns;
/**
* Returns true if the object contains a given value
* @method hasValue
* @static
* @param o an object.
* @param v the value to query.
* @return {boolean} true if the object contains the value.
*/
O.hasValue = function(o, v) {
return (Y.Array.indexOf(O.values(o), v) > -1);
};
/**
* 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.
*
* @method owns
* @static
* @param o {any} The object being testing.
* @param p {string} the property to look for.
* @return {boolean} true if the object has the property on the instance.
*/
O.owns = owns;
/**
* Executes a function on each item. The function
* receives the value, the key, and the object
* as parameters (in that order).
* @method each
* @static
* @param o the object to iterate.
* @param f {Function} the function to execute on each item. The function
* receives three arguments: the value, the the key, the full object.
* @param c the execution context.
* @param proto {boolean} include proto.
* @return {YUI} the YUI instance.
*/
O.each = function(o, f, c, proto) {
var s = c || Y, i;
for (i in o) {
if (proto || owns(o, i)) {
f.call(s, o[i], i, o);
}
}
return Y;
};
/**
* Executes a function on each item, but halts if the
* function returns true. The function
* receives the value, the key, and the object
* as paramters (in that order).
* @method some
* @static
* @param o the object to iterate.
* @param f {Function} the function to execute on each item. The function
* receives three arguments: the value, the the key, the full object.
* @param c the execution context.
* @param proto {boolean} include proto.
* @return {boolean} true if any execution of the function returns true,
* false otherwise.
*/
O.some = function(o, f, c, proto) {
var s = c || Y, i;
for (i in o) {
if (proto || owns(o, i)) {
if (f.call(s, o[i], i, o)) {
return true;
}
}
}
return false;
};
/**
* Retrieves the sub value at the provided path,
* from the value object provided.
*
* @method getValue
* @static
* @param o The object from which to extract the property value.
* @param path {Array} A path array, specifying the object traversal path
* from which to obtain the sub value.
* @return {Any} The value stored in the path, undefined if not found,
* undefined if the source is not an object. Returns the source object
* if an empty path is provided.
*/
O.getValue = function(o, path) {
if (!Y.Lang.isObject(o)) {
return UNDEF;
}
var i,
p = Y.Array(path),
l = p.length;
for (i = 0; o !== UNDEF && i < l; i++) {
o = o[p[i]];
}
return o;
};
/**
* Sets the sub-attribute value at the provided path on the
* value object. Returns the modified value object, or
* undefined if the path is invalid.
*
* @method setValue
* @static
* @param o The object on which to set the sub value.
* @param path {Array} A path array, specifying the object traversal path
* at which to set the sub value.
* @param val {Any} The new value for the sub-attribute.
* @return {Object} The modified object, with the new sub value set, or
* undefined, if the path was invalid.
*/
O.setValue = function(o, path, val) {
var i,
p = Y.Array(path),
leafIdx = p.length - 1,
ref = o;
if (leafIdx >= 0) {
for (i = 0; ref !== UNDEF && i < leafIdx; i++) {
ref = ref[p[i]];
}
if (ref !== UNDEF) {
ref[p[i]] = val;
} else {
return UNDEF;
}
}
return o;
};
/**
* Returns true if the object has no properties of its own
* @method isEmpty
* @static
* @return {boolean} true if the object is empty.
* @since 3.2.0
*/
O.isEmpty = function(o) {
for (var i in o) {
if (owns(o, i)) {
return false;
}
}
return true;
};
/**
* The YUI module contains the components required for building the YUI seed
* file. This includes the script loading mechanism, a simple queue, and the
* core utilities for the library.
* @module yui
* @submodule yui-base
*/
/**
* YUI user agent detection.
* 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. 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 UA
* @static
*/
/**
* Static method for parsing the UA string. Defaults to assigning it's value to Y.UA
* @static
* @method Env.parseUA
* @param {String} subUA Parse this UA string instead of navigator.userAgent
* @returns {Object} The Y.UA object
*/
YUI.Env.parseUA = function(subUA) {
var numberify = function(s) {
var c = 0;
return parseFloat(s.replace(/\./g, function() {
return (c++ == 1) ? '' : '.';
}));
},
win = Y.config.win,
nav = win && win.navigator,
o = {
/**
* Internet Explorer version number or 0. Example: 6
* @property ie
* @type float
* @static
*/
ie: 0,
/**
* Opera version number or 0. Example: 9.2
* @property opera
* @type float
* @static
*/
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
* * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7 * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8 * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81 * Firefox 3.0 <-- 1.9 * Firefox 3.5 <-- 1.91 ** @property gecko * @type float * @static */ gecko: 0, /** * AppleWebKit version. KHTML browsers that are not WebKit browsers * will evaluate to 1, other browsers 0. Example: 418.9 *
* 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). * 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. ** http://en.wikipedia.org/wiki/Safari_version_history * @property webkit * @type float * @static */ webkit: 0, /** * Chrome will be detected as webkit, but this property will also * be populated with the Chrome version number * @property chrome * @type float * @static */ chrome: 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 * @static */ mobile: null, /** * Adobe AIR version number or 0. Only populated if webkit is detected. * Example: 1.0 * @property air * @type float */ air: 0, /** * Detects Apple iPad's OS version * @property ipad * @type float * @static */ ipad: 0, /** * Detects Apple iPhone's OS version * @property iphone * @type float * @static */ iphone: 0, /** * Detects Apples iPod's OS version * @property ipod * @type float * @static */ ipod: 0, /** * General truthy check for iPad, iPhone or iPod * @property ios * @type float * @static */ ios: null, /** * Detects Googles Android OS version * @property android * @type float * @static */ android: 0, /** * Detects Palms WebOS version * @property webos * @type float * @static */ webos: 0, /** * Google Caja version number or 0. * @property caja * @type float */ caja: nav && 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 = subUA || nav && nav.userAgent, loc = win && win.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'; } else if ((/rhino/i).test(ua)) { o.os = 'rhino'; } // 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 = numberify(m[1]); // Mobile browser check if (/ Mobile\//.test(ua)) { o.mobile = 'Apple'; // iPhone or iPod Touch m = ua.match(/OS ([^\s]*)/); if (m && m[1]) { m = numberify(m[1].replace('_', '.')); } o.ios = m; o.ipad = o.ipod = o.iphone = 0; m = ua.match(/iPad|iPod|iPhone/); if (m && m[0]) { o[m[0].toLowerCase()] = o.ios; } } else { m = ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/); if (m) { // Nokia N-series, Android, webOS, ex: NokiaN95 o.mobile = m[0]; } if (/webOS/.test(ua)) { o.mobile = 'WebOS'; m = ua.match(/webOS\/([^\s]*);/); if (m && m[1]) { o.webos = numberify(m[1]); } } if (/ Android/.test(ua)) { o.mobile = 'Android'; m = ua.match(/Android ([^\s]*);/); if (m && m[1]) { o.android = numberify(m[1]); } } } m = ua.match(/Chrome\/([^\s]*)/); if (m && m[1]) { o.chrome = numberify(m[1]); // Chrome } else { 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 = numberify(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 = numberify(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 = numberify(m[1]); } } } } } } YUI.Env.UA = o; return o; }; Y.UA = YUI.Env.UA || YUI.Env.parseUA(); }, '3.3.0' ); YUI.add('get', function(Y) { /** * Provides a mechanism to fetch remote resources and * insert them into a document. * @module yui * @submodule get */ var ua = Y.UA, L = Y.Lang, TYPE_JS = 'text/javascript', TYPE_CSS = 'text/css', STYLESHEET = 'stylesheet'; /** * Fetches and inserts one or more script or link nodes into the document * @class Get * @static */ Y.Get = function() { /** * hash of queues to manage multiple requests * @property queues * @private */ var _get, _purge, _track, queues = {}, /** * queue index used to generate transaction ids * @property qidx * @type int * @private */ qidx = 0, /** * interal property used to prevent multiple simultaneous purge * processes * @property purging * @type boolean * @private */ purging, /** * Generates an HTML element, this is not appended to a document * @method _node * @param {string} type the type of element. * @param {string} attr the attributes. * @param {Window} win optional window to create the element in. * @return {HTMLElement} the generated node. * @private */ _node = function(type, attr, win) { var w = win || Y.config.win, d = w.document, n = d.createElement(type), i; for (i in attr) { if (attr[i] && attr.hasOwnProperty(i)) { n.setAttribute(i, attr[i]); } } return n; }, /** * Generates a link node * @method _linkNode * @param {string} url the url for the css file. * @param {Window} win optional window to create the node in. * @param {object} attributes optional attributes collection to apply to the * new node. * @return {HTMLElement} the generated node. * @private */ _linkNode = function(url, win, attributes) { var o = { id: Y.guid(), type: TYPE_CSS, rel: STYLESHEET, href: url }; if (attributes) { Y.mix(o, attributes); } return _node('link', o, win); }, /** * Generates a script node * @method _scriptNode * @param {string} url the url for the script file. * @param {Window} win optional window to create the node in. * @param {object} attributes optional attributes collection to apply to the * new node. * @return {HTMLElement} the generated node. * @private */ _scriptNode = function(url, win, attributes) { var o = { id: Y.guid(), type: TYPE_JS }; if (attributes) { Y.mix(o, attributes); } o.src = url; return _node('script', o, win); }, /** * Returns the data payload for callback functions. * @method _returnData * @param {object} q the queue. * @param {string} msg the result message. * @param {string} result the status message from the request. * @return {object} the state data from the request. * @private */ _returnData = function(q, msg, result) { return { tId: q.tId, win: q.win, data: q.data, nodes: q.nodes, msg: msg, statusText: result, purge: function() { _purge(this.tId); } }; }, /** * The transaction is finished * @method _end * @param {string} id the id of the request. * @param {string} msg the result message. * @param {string} result the status message from the request. * @private */ _end = function(id, msg, result) { var q = queues[id], sc; if (q && q.onEnd) { sc = q.context || q; q.onEnd.call(sc, _returnData(q, msg, result)); } }, /* * 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 {string} id the id of the request * @private */ _fail = function(id, msg) { var q = queues[id], sc; if (q.timer) { // q.timer.cancel(); clearTimeout(q.timer); } // execute failure callback if (q.onFailure) { sc = q.context || q; q.onFailure.call(sc, _returnData(q, msg)); } _end(id, msg, 'failure'); }, /** * The request is complete, so executing the requester's callback * @method _finish * @param {string} id the id of the request. * @private */ _finish = function(id) { var q = queues[id], msg, sc; if (q.timer) { // q.timer.cancel(); clearTimeout(q.timer); } q.finished = true; if (q.aborted) { msg = 'transaction ' + id + ' was aborted'; _fail(id, msg); return; } // execute success callback if (q.onSuccess) { sc = q.context || q; q.onSuccess.call(sc, _returnData(q)); } _end(id, msg, 'OK'); }, /** * Timeout detected * @method _timeout * @param {string} id the id of the request. * @private */ _timeout = function(id) { var q = queues[id], sc; if (q.onTimeout) { sc = q.context || q; q.onTimeout.call(sc, _returnData(q)); } _end(id, 'timeout', 'timeout'); }, /** * Loads the next item for a given request * @method _next * @param {string} id the id of the request. * @param {string} loaded the url that was just loaded, if any. * @return {string} the result. * @private */ _next = function(id, loaded) { var q = queues[id], msg, w, d, h, n, url, s, insertBefore; if (q.timer) { // q.timer.cancel(); clearTimeout(q.timer); } if (q.aborted) { 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 = (L.isString(q.url)) ? [q.url] : q.url; if (q.varName) { q.varName = (L.isString(q.varName)) ? [q.varName] : q.varName; } } w = q.win; d = w.document; h = d.getElementsByTagName('head')[0]; if (q.url.length === 0) { _finish(id); return; } 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) { // q.timer = L.later(q.timeout, q, _timeout, id); q.timer = setTimeout(function() { _timeout(id); }, q.timeout); } 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'. Work around // IE bug if there is a base tag. insertBefore = q.insertBefore || d.getElementsByTagName('base')[0]; if (insertBefore) { s = _get(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 */ _autoPurge = function() { if (purging) { return; } purging = true; var i, q; for (i in queues) { if (queues.hasOwnProperty(i)) { q = queues[i]; if (q.autopurge && q.finished) { _purge(q.tId); delete queues[i]; } } } purging = false; }, /** * Saves the state for the request and begins loading * the requested urls * @method queue * @param {string} type the type of node to insert. * @param {string} url the url to load. * @param {object} opts the hash of options for this request. * @return {object} transaction object. * @private */ _queue = function(type, url, opts) { opts = opts || {}; var id = 'q' + (qidx++), q, thresh = opts.purgethreshold || Y.Get.PURGE_THRESH; if (qidx % thresh === 0) { _autoPurge(); } queues[id] = Y.merge(opts, { tId: id, type: type, url: url, finished: false, nodes: [] }); q = queues[id]; q.win = q.win || Y.config.win; q.context = q.context || q; q.autopurge = ('autopurge' in q) ? q.autopurge : (type === 'script') ? true : false; q.attributes = q.attributes || {}; q.attributes.charset = opts.charset || q.attributes.charset || 'utf-8'; _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 {string} type the type of node to track. * @param {HTMLElement} n the node to track. * @param {string} id the id of the request. * @param {string} url the url that is being loaded. * @param {Window} win the targeted window. * @param {int} qlength the number of remaining items in the queue, * including this one. * @param {Function} trackfn function to execute when finished * the default is _next. * @private */ _track = function(type, n, id, url, win, qlength, trackfn) { var f = trackfn || _next; // IE supports the readystatechange event for script and css nodes // Opera only for script nodes. Opera support onload for script // nodes, but this doesn't fire when there is a load failure. // The onreadystatechange appears to be a better way to respond // to both success and failure. 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 no longer supported } else if (ua.webkit) { if (type === 'script') { // Safari 3.x supports the load event for script nodes (DOM2) n.addEventListener('load', function() { 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); }; n.onerror = function(e) { _fail(id, e + ': ' + url); }; } }; _get = function(nId, tId) { var q = queues[tId], n = (L.isString(nId)) ? q.win.document.getElementById(nId) : nId; if (!n) { _fail(tId, 'target node not found: ' + nId); } return n; }; /** * Removes the nodes for the specified queue * @method _purge * @param {string} tId the transaction id. * @private */ _purge = function(tId) { var n, l, d, h, s, i, node, attr, insertBefore, q = queues[tId]; if (q) { n = q.nodes; l = n.length; d = q.win.document; h = d.getElementsByTagName('head')[0]; insertBefore = q.insertBefore || d.getElementsByTagName('base')[0]; if (insertBefore) { s = _get(insertBefore, tId); if (s) { h = s.parentNode; } } for (i = 0; i < l; i = i + 1) { node = n[i]; if (node.clearAttributes) { node.clearAttributes(); } else { for (attr in node) { if (node.hasOwnProperty(attr)) { delete node[attr]; } } } h.removeChild(node); } } q.nodes = []; }; return { /** * The number of request required before an automatic purge. * Can be configured via the 'purgethreshold' config * property PURGE_THRESH * @static * @type int * @default 20 * @private */ PURGE_THRESH: 20, /** * Called by the the helper for detecting script load in Safari * @method _finalize * @static * @param {string} id the transaction id. * @private */ _finalize: function(id) { setTimeout(function() { _finish(id); }, 0); }, /** * Abort a transaction * @method abort * @static * @param {string|object} o Either the tId or the object returned from * script() or css(). */ abort: function(o) { var id = (L.isString(o)) ? o : o.tId, 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 {string|string[]} url the url or urls to the script(s). * @param {object} opts Options: *
* Y.Get.script( * ["http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js", * "http://yui.yahooapis.com/2.5.2/build/event/event-min.js"], * { * onSuccess: function(o) { * this.log("won't cause error because Y is the context"); * // immediately * }, * onFailure: function(o) { * }, * onTimeout: function(o) { * }, * data: "foo", * timeout: 10000, // 10 second timeout * context: Y, // make the YUI instance * // win: otherframe // target another window/frame * autopurge: true // allow the utility to choose when to * // remove the nodes * purgetheshold: 1 // purge previous transaction before * // next transaction * });. ** @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 {string} url the url or urls to the css file(s). * @param {object} opts Options: *
* Y.Get.css("http://localhost/css/menu.css"); **
* Y.Get.css( * ["http://localhost/css/menu.css", * insertBefore: 'custom-styles' // nodes will be inserted * // before the specified node * });. ** @return {tId: string} an object containing info about the * transaction. */ css: function(url, opts) { return _queue('css', url, opts); } }; }(); }, '3.3.0' ,{requires:['yui-base']}); YUI.add('features', function(Y) { var feature_tests = {}; Y.mix(Y.namespace('Features'), { tests: feature_tests, add: function(cat, name, o) { feature_tests[cat] = feature_tests[cat] || {}; feature_tests[cat][name] = o; }, all: function(cat, args) { var cat_o = feature_tests[cat], // results = {}; result = ''; if (cat_o) { Y.Object.each(cat_o, function(v, k) { // results[k] = Y.Features.test(cat, k, args); result += k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0) + ';'; }); } return result; }, test: function(cat, name, args) { args = args || []; var result, ua, test, cat_o = feature_tests[cat], feature = cat_o && cat_o[name]; if (!feature) { } else { result = feature.result; if (Y.Lang.isUndefined(result)) { ua = feature.ua; if (ua) { result = (Y.UA[ua]); } test = feature.test; if (test && ((!ua) || result)) { result = test.apply(Y, args); } feature.result = result; } } return result; } }); // Y.Features.add("load", "1", {}); // Y.Features.test("load", "1"); // caps=1:1;2:0;3:1; /* This file is auto-generated by src/loader/meta_join.py */ var add = Y.Features.add; // autocomplete-list-keys-sniff.js add('load', '0', { "test": function (Y) { // Only add keyboard support to autocomplete-list if this doesn't appear to // be an iOS or Android-based mobile device. // // There's currently no feasible way to actually detect whether a device has // a hardware keyboard, so this sniff will have to do. It can easily be // overridden by manually loading the autocomplete-list-keys module. // // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari // doesn't fire the keyboard events used by AutoCompleteList, so there's // no point loading the -keys module even when a bluetooth keyboard may be // available. return !(Y.UA.ios || Y.UA.android); }, "trigger": "autocomplete-list" }); // ie-style-test.js add('load', '1', { "test": function (Y) { var testFeature = Y.Features.test, addFeature = Y.Features.add, WINDOW = Y.config.win, DOCUMENT = Y.config.doc, DOCUMENT_ELEMENT = 'documentElement', ret = false; addFeature('style', 'computedStyle', { test: function() { return WINDOW && 'getComputedStyle' in WINDOW; } }); addFeature('style', 'opacity', { test: function() { return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style; } }); ret = (!testFeature('style', 'opacity') && !testFeature('style', 'computedStyle')); return ret; }, "trigger": "dom-style" }); // 0 add('load', '2', { "trigger": "widget-base", "ua": "ie" }); // ie-base-test.js add('load', '3', { "test": function(Y) { var imp = Y.config.doc && Y.config.doc.implementation; return (imp && (!imp.hasFeature('Events', '2.0'))); }, "trigger": "node-base" }); // dd-gestures-test.js add('load', '4', { "test": function(Y) { return (Y.config.win && ('ontouchstart' in Y.config.win && !Y.UA.chrome)); }, "trigger": "dd-drag" }); // history-hash-ie-test.js add('load', '5', { "test": function (Y) { var docMode = Y.config.doc.documentMode; return Y.UA.ie && (!('onhashchange' in Y.config.win) || !docMode || docMode < 8); }, "trigger": "history-hash" }); }, '3.3.0' ,{requires:['yui-base']}); YUI.add('rls', function(Y) { /** * Implentation for building the remote loader service url. * @method _rls * @param {Array} what the requested modules. * @since 3.2.0 * @return {string} the url for the remote loader service call. */ Y._rls = function(what) { var config = Y.config, // the configuration rls = config.rls || { m: 1, // required in the template v: Y.version, gv: config.gallery, env: 1, // required in the template lang: config.lang, '2in3v': config['2in3'], '2v': config.yui2, filt: config.filter, filts: config.filters, tests: 1 // required in the template }, // The rls base path rls_base = config.rls_base || 'load?', // the template rls_tmpl = config.rls_tmpl || function() { var s = '', param; for (param in rls) { if (param in rls && rls[param]) { s += param + '={' + param + '}&'; } } // console.log('rls_tmpl: ' + s); return s; }(), url; // update the request rls.m = what; rls.env = Y.Object.keys(YUI.Env.mods); rls.tests = Y.Features.all('load', [Y]); url = Y.Lang.sub(rls_base + rls_tmpl, rls); config.rls = rls; config.rls_tmpl = rls_tmpl; // console.log(url); return url; }; }, '3.3.0' ,{requires:['get','features']}); YUI.add('intl-base', function(Y) { /** * The Intl utility provides a central location for managing sets of * localized resources (strings and formatting patterns). * * @class Intl * @uses EventTarget * @static */ var SPLIT_REGEX = /[, ]/; Y.mix(Y.namespace('Intl'), { /** * Returns the language among those available that * best matches the preferred language list, using the Lookup * algorithm of BCP 47. * If none of the available languages meets the user's preferences, * then "" is returned. * Extended language ranges are not supported. * * @method lookupBestLang * @param {String[] | String} preferredLanguages The list of preferred * languages in descending preference order, represented as BCP 47 * language tags. A string array or a comma-separated list. * @param {String[]} availableLanguages The list of languages * that the application supports, represented as BCP 47 language * tags. * * @return {String} The available language that best matches the * preferred language list, or "". * @since 3.1.0 */ lookupBestLang: function(preferredLanguages, availableLanguages) { var i, language, result, index; // check whether the list of available languages contains language; // if so return it function scan(language) { var i; for (i = 0; i < availableLanguages.length; i += 1) { if (language.toLowerCase() === availableLanguages[i].toLowerCase()) { return availableLanguages[i]; } } } if (Y.Lang.isString(preferredLanguages)) { preferredLanguages = preferredLanguages.split(SPLIT_REGEX); } for (i = 0; i < preferredLanguages.length; i += 1) { language = preferredLanguages[i]; if (!language || language === '*') { continue; } // check the fallback sequence for one language while (language.length > 0) { result = scan(language); if (result) { return result; } else { index = language.lastIndexOf('-'); if (index >= 0) { language = language.substring(0, index); // one-character subtags get cut along with the // following subtag if (index >= 2 && language.charAt(index - 2) === '-') { language = language.substring(0, index - 2); } } else { // nothing available for this language break; } } } } return ''; } }); }, '3.3.0' ,{requires:['yui-base']}); YUI.add('yui-log', function(Y) { /** * Provides console log capability and exposes a custom event for * console implementations. * @module yui * @submodule yui-log */ var INSTANCE = Y, LOGEVENT = 'yui:log', UNDEFINED = 'undefined', LEVELS = { debug: 1, info: 1, warn: 1, error: 1 }; /** * If the 'debug' config is true, a 'yui:log' event will be * dispatched, which the Console widget and anything else * can consume. If the 'useBrowserConsole' config is true, it will * write to the browser console if available. YUI-specific log * messages will only be present in the -debug versions of the * JS files. The build system is supposed to remove log statements * from the raw and minified versions of the files. * * @method log * @for YUI * @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). * @param {boolean} silent If true, the log event won't fire. * @return {YUI} YUI instance. */ INSTANCE.log = function(msg, cat, src, silent) { var bail, excl, incl, m, f, Y = INSTANCE, c = Y.config, publisher = (Y.fire) ? Y : YUI.Env.globalEvents; // suppress log message if the config is off or the event stack // or the event call stack contains a consumer of the yui:log event if (c.debug) { // apply source filters if (src) { excl = c.logExclude; incl = c.logInclude; if (incl && !(src in incl)) { bail = 1; } else if (excl && (src in excl)) { bail = 1; } } if (!bail) { if (c.useBrowserConsole) { m = (src) ? src + ': ' + msg : msg; if (Y.Lang.isFunction(c.logFn)) { c.logFn.call(Y, msg, cat, src); } else if (typeof console != UNDEFINED && console.log) { f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log'; console[f](m); } else if (typeof opera != UNDEFINED) { opera.postError(m); } } if (publisher && !silent) { if (publisher == Y && (!publisher.getEvent(LOGEVENT))) { publisher.publish(LOGEVENT, { broadcast: 2 }); } publisher.fire(LOGEVENT, { msg: msg, cat: cat, src: src }); } } } return Y; }; /** * Write a system message. This message will be preserved in the * minified and raw versions of the YUI files, unlike log statements. * @method message * @for YUI * @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). * @param {boolean} silent If true, the log event won't fire. * @return {YUI} YUI instance. */ INSTANCE.message = function() { return INSTANCE.log.apply(INSTANCE, arguments); }; }, '3.3.0' ,{requires:['yui-base']}); YUI.add('yui-later', function(Y) { /** * Provides a setTimeout/setInterval wrapper * @module yui * @submodule yui-later */ /** * 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 * @for YUI * @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 {object} a timer object. Call the cancel() method on this * object to stop the timer. */ Y.later = function(when, o, fn, data, periodic) { when = when || 0; var m = fn, f, id; if (o && Y.Lang.isString(fn)) { m = o[fn]; } f = !Y.Lang.isUndefined(data) ? function() { m.apply(o, Y.Array(data)); } : function() { m.call(o); }; id = (periodic) ? setInterval(f, when) : setTimeout(f, when); return { id: id, interval: periodic, cancel: function() { if (this.interval) { clearInterval(id); } else { clearTimeout(id); } } }; }; Y.Lang.later = Y.later; }, '3.3.0' ,{requires:['yui-base']}); YUI.add('yui-throttle', function(Y) { /** * Provides a throttle/limiter for function calls * @module yui * @submodule yui-throttle */ /*! Based on work by Simon Willison: http://gist.github.com/292562 */ /** * Throttles a call to a method based on the time between calls. * @method throttle * @for YUI * @param fn {function} The function call to throttle. * @param ms {int} The number of milliseconds to throttle the method call. * Can set globally with Y.config.throttleTime or by call. Passing a -1 will * disable the throttle. Defaults to 150. * @return {function} Returns a wrapped function that calls fn throttled. * @since 3.1.0 */ Y.throttle = function(fn, ms) { ms = (ms) ? ms : (Y.config.throttleTime || 150); if (ms === -1) { return (function() { fn.apply(null, arguments); }); } var last = Y.Lang.now(); return (function() { var now = Y.Lang.now(); if (now - last > ms) { last = now; fn.apply(null, arguments); } }); }; }, '3.3.0' ,{requires:['yui-base']}); YUI.add('yui', function(Y){}, '3.3.0' ,{use:['yui-base','get','features','rls','intl-base','yui-log','yui-later','yui-throttle']}); YUI.add('oop', function(Y) { /** * Supplies object inheritance and manipulation utilities. This adds * additional functionaity to what is provided in yui-base, and the * methods are applied directly to the YUI instance. This module * is required for most YUI components. * @module oop */ /** * The following methods are added to the YUI instance * @class YUI~oop */ var L = Y.Lang, A = Y.Array, OP = Object.prototype, CLONE_MARKER = '_~yuim~_', EACH = 'each', SOME = 'some', dispatch = function(o, f, c, proto, action) { if (o && o[action] && o !== Y) { return o[action].call(o, f, c); } else { switch (A.test(o)) { case 1: return A[action](o, f, c); case 2: return A[action](Y.Array(o, 0, true), f, c); default: return Y.Object[action](o, f, c, proto); } } }; /** * Applies prototype properties from the supplier to the receiver. * The receiver can be a constructor or an instance. * @method augment * @param {function} r the object to receive the augmentation. * @param {function} s the object that supplies the properties to augment. * @param {boolean} ov if true, properties already on the receiver * will be overwritten if found on the supplier. * @param {string[]} wl a whitelist. If supplied, only properties in * this list will be applied to the receiver. * @param {Array | Any} args arg or arguments to apply to the supplier * constructor when initializing. * @return {object} the augmented object. * * @todo constructor optional? * @todo understanding what an instance is augmented with * @todo best practices for overriding sequestered methods. */ Y.augment = function(r, s, ov, wl, args) { var sProto = s.prototype, newProto = null, construct = s, a = (args) ? Y.Array(args) : [], rProto = r.prototype, target = rProto || r, applyConstructor = false, sequestered, replacements; // working on a class, so apply constructor infrastructure if (rProto && construct) { sequestered = {}; replacements = {}; newProto = {}; // sequester all of the functions in the supplier and replace with // one that will restore all of them. Y.Object.each(sProto, function(v, k) { replacements[k] = function() { // overwrite the prototype with all of the sequestered functions, // but only if it hasn't been overridden for (var i in sequestered) { if (sequestered.hasOwnProperty(i) && (this[i] === replacements[i])) { this[i] = sequestered[i]; } } // apply the constructor construct.apply(this, a); // apply the original sequestered function return sequestered[k].apply(this, arguments); }; if ((!wl || (k in wl)) && (ov || !(k in this))) { if (L.isFunction(v)) { // sequester the function sequestered[k] = v; // replace the sequestered function with a function that will // restore all sequestered functions and exectue the constructor. this[k] = replacements[k]; } else { this[k] = v; } } }, newProto, true); // augmenting an instance, so apply the constructor immediately } else { applyConstructor = true; } Y.mix(target, newProto || sProto, ov, wl); if (applyConstructor) { s.apply(target, a); } return r; }; /** * Applies object properties from the supplier to the receiver. If * the target has the property, and the property is an object, the target * object will be augmented with the supplier's value. If the property * is an array, the suppliers value will be appended to the target. * @method aggregate * @param {function} r the object to receive the augmentation. * @param {function} s the object that supplies the properties to augment. * @param {boolean} ov if true, properties already on the receiver * will be overwritten if found on the supplier. * @param {string[]} wl a whitelist. If supplied, only properties in * this list will be applied to the receiver. * @return {object} the extended object. */ Y.aggregate = function(r, s, ov, wl) { return Y.mix(r, s, ov, wl, 0, true); }; /** * 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 * @param {function} r the object to modify. * @param {function} s the object to inherit. * @param {object} px prototype properties to add/override. * @param {object} sx static properties to add/override. * @return {object} the extended object. */ Y.extend = function(r, s, px, sx) { if (!s || !r) { Y.error('extend failed, verify dependencies'); } var sp = s.prototype, rp = Y.Object(sp); r.prototype = rp; rp.constructor = r; r.superclass = sp; // assign constructor property if (s != Object && sp.constructor == OP.constructor) { sp.constructor = s; } // add prototype overrides if (px) { Y.mix(rp, px, true); } // add object overrides if (sx) { Y.mix(r, sx, true); } return r; }; /** * Executes the supplied function for each item in * a collection. Supports arrays, objects, and * Y.NodeLists * @method each * @param {object} o the object to iterate. * @param {function} f the function to execute. This function * receives the value, key, and object as parameters. * @param {object} c the execution context for the function. * @param {boolean} proto if true, prototype properties are * iterated on objects. * @return {YUI} the YUI instance. */ Y.each = function(o, f, c, proto) { return dispatch(o, f, c, proto, EACH); }; /** * Executes the supplied function for each item in * a collection. The operation stops if the function * returns true. Supports arrays, objects, and * Y.NodeLists. * @method some * @param {object} o the object to iterate. * @param {function} f the function to execute. This function * receives the value, key, and object as parameters. * @param {object} c the execution context for the function. * @param {boolean} proto if true, prototype properties are * iterated on objects. * @return {boolean} true if the function ever returns true, * false otherwise. */ Y.some = function(o, f, c, proto) { return dispatch(o, f, c, proto, SOME); }; /** * Deep obj/array copy. Function clones are actually * wrappers around the original function. * Array-like objects are treated as arrays. * Primitives are returned untouched. Optionally, a * function can be provided to handle other data types, * filter keys, validate values, etc. * * @method clone * @param {object} o what to clone. * @param {boolean} safe if true, objects will not have prototype * items from the source. If false, they will. In this case, the * original is initially protected, but the clone is not completely * immune from changes to the source object prototype. Also, cloned * prototype items that are deleted from the clone will result * in the value of the source prototype being exposed. If operating * on a non-safe clone, items should be nulled out rather than deleted. * @param {function} f optional function to apply to each item in a * collection; it will be executed prior to applying the value to * the new object. Return false to prevent the copy. * @param {object} c optional execution context for f. * @param {object} owner Owner object passed when clone is iterating * an object. Used to set up context for cloned functions. * @param {object} cloned hash of previously cloned objects to avoid * multiple clones. * @return {Array|Object} the cloned object. */ Y.clone = function(o, safe, f, c, owner, cloned) { if (!L.isObject(o)) { return o; } // @todo cloning YUI instances doesn't currently work if (Y.instanceOf(o, YUI)) { return o; } var o2, marked = cloned || {}, stamp, yeach = Y.each; switch (L.type(o)) { case 'date': return new Date(o); case 'regexp': // if we do this we need to set the flags too // return new RegExp(o.source); return o; case 'function': // o2 = Y.bind(o, owner); // break; return o; case 'array': o2 = []; break; default: // #2528250 only one clone of a given object should be created. if (o[CLONE_MARKER]) { return marked[o[CLONE_MARKER]]; } stamp = Y.guid(); o2 = (safe) ? {} : Y.Object(o); o[CLONE_MARKER] = stamp; marked[stamp] = o; } // #2528250 don't try to clone element properties if (!o.addEventListener && !o.attachEvent) { yeach(o, function(v, k) { if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) { if (k !== CLONE_MARKER) { if (k == 'prototype') { // skip the prototype // } else if (o[k] === o) { // this[k] = this; } else { this[k] = Y.clone(v, safe, f, c, owner || o, marked); } } } }, o2); } if (!cloned) { Y.Object.each(marked, function(v, k) { if (v[CLONE_MARKER]) { try { delete v[CLONE_MARKER]; } catch (e) { v[CLONE_MARKER] = null; } } }, this); marked = null; } return o2; }; /** * Returns a function that will execute the supplied function in the * supplied object's context, optionally adding any additional * supplied parameters to the beginning of the arguments collection the * supplied to the function. * * @method bind * @param {Function|String} f the function to bind, or a function name * to execute on the context object. * @param {object} c the execution context. * @param {any} args* 0..n arguments to include before the arguments the * function is executed with. * @return {function} the wrapped function. */ Y.bind = function(f, c) { var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null; return function() { var fn = L.isString(f) ? c[f] : f, args = (xargs) ? xargs.concat(Y.Array(arguments, 0, true)) : arguments; return fn.apply(c || fn, args); }; }; /** * Returns a function that will execute the supplied function in the * supplied object's context, optionally adding any additional * supplied parameters to the end of the arguments the function * is executed with. * * @method rbind * @param {Function|String} f the function to bind, or a function name * to execute on the context object. * @param {object} c the execution context. * @param {any} args* 0..n arguments to append to the end of * arguments collection supplied to the function. * @return {function} the wrapped function. */ Y.rbind = function(f, c) { var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null; return function() { var fn = L.isString(f) ? c[f] : f, args = (xargs) ? Y.Array(arguments, 0, true).concat(xargs) : arguments; return fn.apply(c || fn, args); }; }; }, '3.3.0' ); YUI.add('dom-base', function(Y) { (function(Y) { /** * The DOM utility provides a cross-browser abtraction layer * normalizing DOM tasks, and adds extra helper functionality * for other common tasks. * @module dom * @submodule dom-base * @for DOM * */ /** * Provides DOM helper methods. * @class DOM * */ var NODE_TYPE = 'nodeType', OWNER_DOCUMENT = 'ownerDocument', DOCUMENT_ELEMENT = 'documentElement', DEFAULT_VIEW = 'defaultView', PARENT_WINDOW = 'parentWindow', TAG_NAME = 'tagName', PARENT_NODE = 'parentNode', FIRST_CHILD = 'firstChild', PREVIOUS_SIBLING = 'previousSibling', NEXT_SIBLING = 'nextSibling', CONTAINS = 'contains', COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition', EMPTY_STRING = '', EMPTY_ARRAY = [], documentElement = Y.config.doc.documentElement, re_tag = /<([a-z]+)/i, createFromDIV = function(html, tag) { var div = Y.config.doc.createElement('div'), ret = true; div.innerHTML = html; if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) { ret = false; } return ret; }, addFeature = Y.Features.add, testFeature = Y.Features.test, Y_DOM = { /** * Returns the HTMLElement with the given ID (Wrapper for document.getElementById). * @method byId * @param {String} id the id attribute * @param {Object} doc optional The document to search. Defaults to current document * @return {HTMLElement | null} The HTMLElement with the id, or null if none found. */ byId: function(id, doc) { // handle dupe IDs and IE name collision return Y_DOM.allById(id, doc)[0] || null; }, /** * Returns the text content of the HTMLElement. * @method getText * @param {HTMLElement} element The html element. * @return {String} The text content of the element (includes text of any descending elements). */ getText: (documentElement.textContent !== undefined) ? function(element) { var ret = ''; if (element) { ret = element.textContent; } return ret || ''; } : function(element) { var ret = ''; if (element) { ret = element.innerText || element.nodeValue; // might be a textNode } return ret || ''; }, /** * Sets the text content of the HTMLElement. * @method setText * @param {HTMLElement} element The html element. * @param {String} content The content to add. */ setText: (documentElement.textContent !== undefined) ? function(element, content) { if (element) { element.textContent = content; } } : function(element, content) { if ('innerText' in element) { element.innerText = content; } else if ('nodeValue' in element) { element.nodeValue = content; } }, /* * Finds the ancestor of the element. * @method ancestor * @param {HTMLElement} element The html element. * @param {Function} fn optional An optional boolean test to apply. * The optional function is passed the current DOM node being tested as its only argument. * If no function is given, the parentNode is returned. * @param {Boolean} testSelf optional Whether or not to include the element in the scan * @return {HTMLElement | null} The matching DOM node or null if none found. */ ancestor: function(element, fn, testSelf) { var ret = null; if (testSelf) { ret = (!fn || fn(element)) ? element : null; } return ret || Y_DOM.elementByAxis(element, PARENT_NODE, fn, null); }, /* * Finds the ancestors of the element. * @method ancestors * @param {HTMLElement} element The html element. * @param {Function} fn optional An optional boolean test to apply. * The optional function is passed the current DOM node being tested as its only argument. * If no function is given, all ancestors are returned. * @param {Boolean} testSelf optional Whether or not to include the element in the scan * @return {Array} An array containing all matching DOM nodes. */ ancestors: function(element, fn, testSelf) { var ancestor = Y_DOM.ancestor.apply(Y_DOM, arguments), ret = (ancestor) ? [ancestor] : []; while ((ancestor = Y_DOM.ancestor(ancestor, fn))) { if (ancestor) { ret.unshift(ancestor); } } return ret; }, /** * Searches the element by the given axis for the first matching element. * @method elementByAxis * @param {HTMLElement} element The html element. * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling). * @param {Function} fn optional An optional boolean test to apply. * @param {Boolean} all optional Whether all node types should be returned, or just element nodes. * The optional function is passed the current HTMLElement being tested as its only argument. * If no function is given, the first element is returned. * @return {HTMLElement | null} The matching element or null if none found. */ elementByAxis: function(element, axis, fn, all) { while (element && (element = element[axis])) { // NOTE: assignment if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) { return element; } } return null; }, /** * Determines whether or not one HTMLElement is or contains another HTMLElement. * @method contains * @param {HTMLElement} element The containing html element. * @param {HTMLElement} needle The html element that may be contained. * @return {Boolean} Whether or not the element is or contains the needle. */ contains: function(element, needle) { var ret = false; if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) { ret = false; } else if (element[CONTAINS]) { if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE ret = element[CONTAINS](needle); } else { ret = Y_DOM._bruteContains(element, needle); } } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) { ret = true; } } return ret; }, /** * Determines whether or not the HTMLElement is part of the document. * @method inDoc * @param {HTMLElement} element The containing html element. * @param {HTMLElement} doc optional The document to check. * @return {Boolean} Whether or not the element is attached to the document. */ inDoc: function(element, doc) { var ret = false, rootNode; if (element && element.nodeType) { (doc) || (doc = element[OWNER_DOCUMENT]); rootNode = doc[DOCUMENT_ELEMENT]; // contains only works with HTML_ELEMENT if (rootNode && rootNode.contains && element.tagName) { ret = rootNode.contains(element); } else { ret = Y_DOM.contains(rootNode, element); } } return ret; }, allById: function(id, root) { root = root || Y.config.doc; var nodes = [], ret = [], i, node; if (root.querySelectorAll) { ret = root.querySelectorAll('[id="' + id + '"]'); } else if (root.all) { nodes = root.all(id); if (nodes) { // root.all may return HTMLElement or HTMLCollection. // some elements are also HTMLCollection (FORM, SELECT). if (nodes.nodeName) { if (nodes.id === id) { // avoid false positive on name ret.push(nodes); nodes = EMPTY_ARRAY; // done, no need to filter } else { // prep for filtering nodes = [nodes]; } } if (nodes.length) { // filter out matches on node.name // and element.id as reference to element with id === 'id' for (i = 0; node = nodes[i++];) { if (node.id === id || (node.attributes && node.attributes.id && node.attributes.id.value === id)) { ret.push(node); } } } } } else { ret = [Y_DOM._getDoc(root).getElementById(id)]; } return ret; }, /** * Creates a new dom node using the provided markup string. * @method create * @param {String} html The markup used to create the element * @param {HTMLDocument} doc An optional document context * @return {HTMLElement|DocumentFragment} returns a single HTMLElement * when creating one node, and a documentFragment when creating * multiple nodes. */ create: function(html, doc) { if (typeof html === 'string') { html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML } doc = doc || Y.config.doc; var m = re_tag.exec(html), create = Y_DOM._create, custom = Y_DOM.creators, ret = null, creator, tag, nodes; if (html != undefined) { // not undefined or null if (m && m[1]) { creator = custom[m[1].toLowerCase()]; if (typeof creator === 'function') { create = creator; } else { tag = creator; } } nodes = create(html, doc, tag).childNodes; if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment" ret = nodes[0].parentNode.removeChild(nodes[0]); } else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected) if (nodes.length === 2) { ret = nodes[0].nextSibling; } else { nodes[0].parentNode.removeChild(nodes[0]); ret = Y_DOM._nl2frag(nodes, doc); } } else { // return multiple nodes as a fragment ret = Y_DOM._nl2frag(nodes, doc); } } return ret; }, _nl2frag: function(nodes, doc) { var ret = null, i, len; if (nodes && (nodes.push || nodes.item) && nodes[0]) { doc = doc || nodes[0].ownerDocument; ret = doc.createDocumentFragment(); if (nodes.item) { // convert live list to static array nodes = Y.Array(nodes, 0, true); } for (i = 0, len = nodes.length; i < len; i++) { ret.appendChild(nodes[i]); } } // else inline with log for minification return ret; }, CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8 'for': 'htmlFor', 'class': 'className' } : { // w3c 'htmlFor': 'for', 'className': 'class' }, /** * Provides a normalized attribute interface. * @method setAttibute * @param {HTMLElement} el The target element for the attribute. * @param {String} attr The attribute to set. * @param {String} val The value of the attribute. */ setAttribute: function(el, attr, val, ieAttr) { if (el && attr && el.setAttribute) { attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; el.setAttribute(attr, val, ieAttr); } }, /** * Provides a normalized attribute interface. * @method getAttibute * @param {HTMLElement} el The target element for the attribute. * @param {String} attr The attribute to get. * @return {String} The current value of the attribute. */ getAttribute: function(el, attr, ieAttr) { ieAttr = (ieAttr !== undefined) ? ieAttr : 2; var ret = ''; if (el && attr && el.getAttribute) { attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; ret = el.getAttribute(attr, ieAttr); if (ret === null) { ret = ''; // per DOM spec } } return ret; }, isWindow: function(obj) { return !!(obj && obj.alert && obj.document); }, _fragClones: {}, _create: function(html, doc, tag) { tag = tag || 'div'; var frag = Y_DOM._fragClones[tag]; if (frag) { frag = frag.cloneNode(false); } else { frag = Y_DOM._fragClones[tag] = doc.createElement(tag); } frag.innerHTML = html; return frag; }, _removeChildNodes: function(node) { while (node.firstChild) { node.removeChild(node.firstChild); } }, /** * Inserts content in a node at the given location * @method addHTML * @param {HTMLElement} node The node to insert into * @param {HTMLElement | Array | HTMLCollection} content The content to be inserted * @param {HTMLElement} where Where to insert the content * If no "where" is given, content is appended to the node * Possible values for "where" *
on
except the
* listener is immediatelly detached when it is executed.
* @method once
* @param type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
once: function() {
var handle = this.on.apply(this, arguments);
handle.batch(function(hand) {
if (hand.sub) {
hand.sub.once = true;
}
});
return handle;
},
/**
* Takes the type parameter passed to 'on' and parses out the
* various pieces that could be included in the type. If the
* event type is passed without a prefix, it will be expanded
* to include the prefix one is supplied or the event target
* is configured with a default prefix.
* @method parseType
* @param {string} type the type
* @param {string} [pre=this._yuievt.config.prefix] the prefix
* @since 3.3.0
* @return {Array} an array containing:
* * the detach category, if supplied,
* * the prefixed event type,
* * whether or not this is an after listener,
* * the supplied event type
*/
parseType: function(type, pre) {
return _parseType(type, pre || this._yuievt.config.prefix);
},
/**
* Subscribe to a custom event hosted by this object
* @method on
* @param type {string} The type of the event
* @param fn {Function} The callback
* @param context {object} optional execution context.
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
* @return the event target or a detach handle per 'chain' config
*/
on: function(type, fn, context) {
var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
Node = Y.Node, n, domevent, isArr;
// full name, args, detachcategory, after
this._monitor('attach', parts[1], {
args: arguments,
category: parts[0],
after: parts[2]
});
if (L.isObject(type)) {
if (L.isFunction(type)) {
return Y.Do.before.apply(Y.Do, arguments);
}
f = fn;
c = context;
args = YArray(arguments, 0, true);
ret = [];
if (L.isArray(type)) {
isArr = true;
}
after = type._after;
delete type._after;
Y.each(type, function(v, k) {
if (L.isObject(v)) {
f = v.fn || ((L.isFunction(v)) ? v : f);
c = v.context || c;
}
var nv = (after) ? AFTER_PREFIX : '';
args[0] = nv + ((isArr) ? v : k);
args[1] = f;
args[2] = c;
ret.push(this.on.apply(this, args));
}, this);
return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
}
detachcategory = parts[0];
after = parts[2];
shorttype = parts[3];
// extra redirection so we catch adaptor events too. take a look at this.
if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) {
args = YArray(arguments, 0, true);
args.splice(2, 0, Node.getDOMNode(this));
return Y.on.apply(Y, args);
}
type = parts[1];
if (Y.instanceOf(this, YUI)) {
adapt = Y.Env.evt.plugins[type];
args = YArray(arguments, 0, true);
args[0] = shorttype;
if (Node) {
n = args[2];
if (Y.instanceOf(n, Y.NodeList)) {
n = Y.NodeList.getDOMNodes(n);
} else if (Y.instanceOf(n, Node)) {
n = Node.getDOMNode(n);
}
domevent = (shorttype in Node.DOM_EVENTS);
// Captures both DOM events and event plugins.
if (domevent) {
args[2] = n;
}
}
// check for the existance of an event adaptor
if (adapt) {
handle = adapt.on.apply(Y, args);
} else if ((!type) || domevent) {
handle = Y.Event._attach(args);
}
}
if (!handle) {
ce = this._yuievt.events[type] || this.publish(type);
handle = ce._on(fn, context, (arguments.length > 3) ? YArray(arguments, 3, true) : null, (after) ? 'after' : true);
}
if (detachcategory) {
store[detachcategory] = store[detachcategory] || {};
store[detachcategory][type] = store[detachcategory][type] || [];
store[detachcategory][type].push(handle);
}
return (this._yuievt.chain) ? this : handle;
},
/**
* subscribe to an event
* @method subscribe
* @deprecated use on
*/
subscribe: function() {
return this.on.apply(this, arguments);
},
/**
* Detach one or more listeners the from the specified event
* @method detach
* @param type {string|Object} Either the handle to the subscriber or the
* type of event. If the type
* is not specified, it will attempt to remove
* the listener from all hosted events.
* @param fn {Function} The subscribed function to unsubscribe, if not
* supplied, all subscribers will be removed.
* @param context {Object} The custom object passed to subscribe. This is
* optional, but if supplied will be used to
* disambiguate multiple listeners that are the same
* (e.g., you subscribe many object using a function
* that lives on the prototype)
* @return {EventTarget} the host
*/
detach: function(type, fn, context) {
var evts = this._yuievt.events, i,
Node = Y.Node, isNode = Node && (Y.instanceOf(this, Node));
// detachAll disabled on the Y instance.
if (!type && (this !== Y)) {
for (i in evts) {
if (evts.hasOwnProperty(i)) {
evts[i].detach(fn, context);
}
}
if (isNode) {
Y.Event.purgeElement(Node.getDOMNode(this));
}
return this;
}
var parts = _parseType(type, this._yuievt.config.prefix),
detachcategory = L.isArray(parts) ? parts[0] : null,
shorttype = (parts) ? parts[3] : null,
adapt, store = Y.Env.evt.handles, detachhost, cat, args,
ce,
keyDetacher = function(lcat, ltype, host) {
var handles = lcat[ltype], ce, i;
if (handles) {
for (i = handles.length - 1; i >= 0; --i) {
ce = handles[i].evt;
if (ce.host === host || ce.el === host) {
handles[i].detach();
}
}
}
};
if (detachcategory) {
cat = store[detachcategory];
type = parts[1];
detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
if (cat) {
if (type) {
keyDetacher(cat, type, detachhost);
} else {
for (i in cat) {
if (cat.hasOwnProperty(i)) {
keyDetacher(cat, i, detachhost);
}
}
}
return this;
}
// If this is an event handle, use it to detach
} else if (L.isObject(type) && type.detach) {
type.detach();
return this;
// extra redirection so we catch adaptor events too. take a look at this.
} else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
args = YArray(arguments, 0, true);
args[2] = Node.getDOMNode(this);
Y.detach.apply(Y, args);
return this;
}
adapt = Y.Env.evt.plugins[shorttype];
// The YUI instance handles DOM events and adaptors
if (Y.instanceOf(this, YUI)) {
args = YArray(arguments, 0, true);
// use the adaptor specific detach code if
if (adapt && adapt.detach) {
adapt.detach.apply(Y, args);
return this;
// DOM event fork
} else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
args[0] = type;
Y.Event.detach.apply(Y.Event, args);
return this;
}
}
// ce = evts[type];
ce = evts[parts[1]];
if (ce) {
ce.detach(fn, context);
}
return this;
},
/**
* detach a listener
* @method unsubscribe
* @deprecated use detach
*/
unsubscribe: function() {
return this.detach.apply(this, arguments);
},
/**
* Removes all listeners from the specified event. If the event type
* is not specified, all listeners from all hosted custom events will
* be removed.
* @method detachAll
* @param type {string} The type, or name of the event
*/
detachAll: function(type) {
return this.detach(type);
},
/**
* Removes all listeners from the specified event. If the event type
* is not specified, all listeners from all hosted custom events will
* be removed.
* @method unsubscribeAll
* @param type {string} The type, or name of the event
* @deprecated use detachAll
*/
unsubscribeAll: function() {
return this.detachAll.apply(this, arguments);
},
/**
* Creates a new custom event of the specified type. If a custom event
* by that name already exists, it will not be re-created. In either
* case the custom event is returned.
*
* @method publish
*
* @param type {string} the type, or name of the event
* @param opts {object} optional config params. Valid properties are:
*
* YUI
's on
method is a unified interface for subscribing to
* most events exposed by YUI. This includes custom events, DOM events, and
* function events. detach
is also provided to remove listeners
* serviced by this function.
*
* The signature that on
accepts varies depending on the type
* of event being consumed. Refer to the specific methods that will
* service a specific request for additional information about subscribing
* to that type of event.
*
* EventTarget
's on
method.
* Y.on('drag:drophit', function() { // start work });
* Event
's
* attach
method.
* Y.on('click', function(e) { // something was clicked }, '#someelement');
* Event.Do
's
* before
method.
* Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');
* on
corresponds to the moment before any default behavior of
* the event. after
works the same way, but these listeners
* execute after the event's default behavior. before
is an
* alias for on
.
*
* @method on
* @param type event type (this parameter does not apply for function events)
* @param fn the callback
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
/**
* Listen for an event one time. Equivalent to on
, except that
* the listener is immediately detached when executed.
* @see on
* @method once
* @param type event type (this parameter does not apply for function events)
* @param fn the callback
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
/**
* after() is a unified interface for subscribing to
* most events exposed by YUI. This includes custom events,
* DOM events, and AOP events. This works the same way as
* the on() function, only it operates after any default
* behavior for the event has executed. @see on
for more
* information.
* @method after
* @param type event type (this parameter does not apply for function events)
* @param fn the callback
* @param context optionally change the value of 'this' in the callback
* @param args* 0..n additional arguments to pass to the callback.
* @return the event target or a detach handle per 'chain' config
* @for YUI
*/
}, '3.3.0' ,{requires:['oop']});
var GLOBAL_ENV = YUI.Env;
if (!GLOBAL_ENV._ready) {
GLOBAL_ENV._ready = function() {
GLOBAL_ENV.DOMReady = true;
GLOBAL_ENV.remove(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
};
// if (!YUI.UA.ie) {
GLOBAL_ENV.add(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
// }
}
YUI.add('event-base', function(Y) {
/*
* DOM event listener abstraction layer
* @module event
* @submodule event-base
*/
/**
* The domready event fires at the moment the browser's DOM is
* usable. In most cases, this is before images are fully
* downloaded, allowing you to provide a more responsive user
* interface.
*
* In YUI 3, domready subscribers will be notified immediately if
* that moment has already passed when the subscription is created.
*
* One exception is if the yui.js file is dynamically injected into
* the page. If this is done, you must tell the YUI instance that
* you did this in order for DOMReady (and window load events) to
* fire normally. That configuration option is 'injected' -- set
* it to true if the yui.js script is not included inline.
*
* This method is part of the 'event-ready' module, which is a
* submodule of 'event'.
*
* @event domready
* @for YUI
*/
Y.publish('domready', {
fireOnce: true,
async: true
});
if (GLOBAL_ENV.DOMReady) {
Y.fire('domready');
} else {
Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready');
}
/**
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
* events.
* @module event
* @submodule event-base
*/
/**
* Wraps a DOM event, properties requiring browser abstraction are
* fixed here. Provids a security layer when required.
* @class DOMEventFacade
* @param ev {Event} the DOM event
* @param currentTarget {HTMLElement} the element the listener was attached to
* @param wrapper {Event.Custom} the custom event wrapper for this DOM event
*/
var ua = Y.UA,
EMPTY = {},
/**
* webkit key remapping required for Safari < 3.1
* @property webkitKeymap
* @private
*/
webkitKeymap = {
63232: 38, // up
63233: 40, // down
63234: 37, // left
63235: 39, // right
63276: 33, // page up
63277: 34, // page down
25: 9, // SHIFT-TAB (Safari provides a different key code in
// this case, even though the shiftKey modifier is set)
63272: 46, // delete
63273: 36, // home
63275: 35 // end
},
/**
* Returns a wrapped node. Intended to be used on event targets,
* so it will return the node's parent if the target is a text
* node.
*
* If accessing a property of the node throws an error, this is
* probably the anonymous div wrapper Gecko adds inside text
* nodes. This likely will only occur when attempting to access
* the relatedTarget. In this case, we now return null because
* the anonymous div is completely useless and we do not know
* what the related target was because we can't even get to
* the element's parent node.
*
* @method resolve
* @private
*/
resolve = function(n) {
if (!n) {
return n;
}
try {
if (n && 3 == n.nodeType) {
n = n.parentNode;
}
} catch(e) {
return null;
}
return Y.one(n);
},
DOMEventFacade = function(ev, currentTarget, wrapper) {
this._event = ev;
this._currentTarget = currentTarget;
this._wrapper = wrapper || EMPTY;
// if not lazy init
this.init();
};
Y.extend(DOMEventFacade, Object, {
init: function() {
var e = this._event,
overrides = this._wrapper.overrides,
x = e.pageX,
y = e.pageY,
c,
currentTarget = this._currentTarget;
this.altKey = e.altKey;
this.ctrlKey = e.ctrlKey;
this.metaKey = e.metaKey;
this.shiftKey = e.shiftKey;
this.type = (overrides && overrides.type) || e.type;
this.clientX = e.clientX;
this.clientY = e.clientY;
this.pageX = x;
this.pageY = y;
c = e.keyCode || e.charCode;
if (ua.webkit && (c in webkitKeymap)) {
c = webkitKeymap[c];
}
this.keyCode = c;
this.charCode = c;
this.which = e.which || e.charCode || c;
// this.button = e.button;
this.button = this.which;
this.target = resolve(e.target);
this.currentTarget = resolve(currentTarget);
this.relatedTarget = resolve(e.relatedTarget);
if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
}
if (this._touch) {
this._touch(e, currentTarget, this._wrapper);
}
},
stopPropagation: function() {
this._event.stopPropagation();
this._wrapper.stopped = 1;
this.stopped = 1;
},
stopImmediatePropagation: function() {
var e = this._event;
if (e.stopImmediatePropagation) {
e.stopImmediatePropagation();
} else {
this.stopPropagation();
}
this._wrapper.stopped = 2;
this.stopped = 2;
},
preventDefault: function(returnValue) {
var e = this._event;
e.preventDefault();
e.returnValue = returnValue || false;
this._wrapper.prevented = 1;
this.prevented = 1;
},
halt: function(immediate) {
if (immediate) {
this.stopImmediatePropagation();
} else {
this.stopPropagation();
}
this.preventDefault();
}
});
DOMEventFacade.resolve = resolve;
Y.DOM2EventFacade = DOMEventFacade;
Y.DOMEventFacade = DOMEventFacade;
/**
* The native event
* @property _event
*/
/**
* The X location of the event on the page (including scroll)
* @property pageX
* @type int
*/
/**
* The Y location of the event on the page (including scroll)
* @property pageY
* @type int
*/
/**
* The keyCode for key events. Uses charCode if keyCode is not available
* @property keyCode
* @type int
*/
/**
* The charCode for key events. Same as keyCode
* @property charCode
* @type int
*/
/**
* The button that was pushed.
* @property button
* @type int
*/
/**
* The button that was pushed. Same as button.
* @property which
* @type int
*/
/**
* Node reference for the targeted element
* @propery target
* @type Node
*/
/**
* Node reference for the element that the listener was attached to.
* @propery currentTarget
* @type Node
*/
/**
* Node reference to the relatedTarget
* @propery relatedTarget
* @type Node
*/
/**
* Number representing the direction and velocity of the movement of the mousewheel.
* Negative is down, the higher the number, the faster. Applies to the mousewheel event.
* @property wheelDelta
* @type int
*/
/**
* Stops the propagation to the next bubble target
* @method stopPropagation
*/
/**
* Stops the propagation to the next bubble target and
* prevents any additional listeners from being exectued
* on the current target.
* @method stopImmediatePropagation
*/
/**
* Prevents the event's default behavior
* @method preventDefault
* @param returnValue {string} sets the returnValue of the event to this value
* (rather than the default false value). This can be used to add a customized
* confirmation query to the beforeunload event).
*/
/**
* Stops the event propagation and prevents the default
* event behavior.
* @method halt
* @param immediate {boolean} if true additional listeners
* on the current target will not be executed
*/
(function() {
/**
* DOM event listener abstraction layer
* @module event
* @submodule event-base
*/
/**
* The event utility provides functions to add and remove event listeners,
* event cleansing. It also tries to automatically remove listeners it
* registers during the unload event.
*
* @class Event
* @static
*/
Y.Env.evt.dom_wrappers = {};
Y.Env.evt.dom_map = {};
var _eventenv = Y.Env.evt,
config = Y.config,
win = config.win,
add = YUI.Env.add,
remove = YUI.Env.remove,
onLoad = function() {
YUI.Env.windowLoaded = true;
Y.Event._load();
remove(win, "load", onLoad);
},
onUnload = function() {
Y.Event._unload();
},
EVENT_READY = 'domready',
COMPAT_ARG = '~yui|2|compat~',
shouldIterate = function(o) {
try {
return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) &&
!o.tagName && !o.alert);
} catch(ex) {
return false;
}
},
Event = function() {
/**
* True after the onload event has fired
* @property _loadComplete
* @type boolean
* @static
* @private
*/
var _loadComplete = false,
/**
* The number of times to poll after window.onload. This number is
* increased if additional late-bound handlers are requested after
* the page load.
* @property _retryCount
* @static
* @private
*/
_retryCount = 0,
/**
* onAvailable listeners
* @property _avail
* @static
* @private
*/
_avail = [],
/**
* Custom event wrappers for DOM events. Key is
* 'event:' + Element uid stamp + event type
* @property _wrappers
* @type Y.Event.Custom
* @static
* @private
*/
_wrappers = _eventenv.dom_wrappers,
_windowLoadKey = null,
/**
* Custom event wrapper map DOM events. Key is
* Element uid stamp. Each item is a hash of custom event
* wrappers as provided in the _wrappers collection. This
* provides the infrastructure for getListeners.
* @property _el_events
* @static
* @private
*/
_el_events = _eventenv.dom_map;
return {
/**
* The number of times we should look for elements that are not
* in the DOM at the time the event is requested after the document
* has been loaded. The default is 1000@amp;40 ms, so it will poll
* for 40 seconds or until all outstanding handlers are bound
* (whichever comes first).
* @property POLL_RETRYS
* @type int
* @static
* @final
*/
POLL_RETRYS: 1000,
/**
* The poll interval in milliseconds
* @property POLL_INTERVAL
* @type int
* @static
* @final
*/
POLL_INTERVAL: 40,
/**
* addListener/removeListener can throw errors in unexpected scenarios.
* These errors are suppressed, the method returns false, and this property
* is set
* @property lastError
* @static
* @type Error
*/
lastError: null,
/**
* poll handle
* @property _interval
* @static
* @private
*/
_interval: null,
/**
* document readystate poll handle
* @property _dri
* @static
* @private
*/
_dri: null,
/**
* True when the document is initially usable
* @property DOMReady
* @type boolean
* @static
*/
DOMReady: false,
/**
* @method startInterval
* @static
* @private
*/
startInterval: function() {
if (!Event._interval) {
Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL);
}
},
/**
* Executes the supplied callback when the item with the supplied
* id is found. This is meant to be used to execute behavior as
* soon as possible as the page loads. If you use this after the
* initial page load it will poll for a fixed time for the element.
* The number of times it will poll and the frequency are
* configurable. By default it will poll for 10 seconds.
*
* The callback is executed with a single parameter: * the custom object parameter, if provided.
* * @method onAvailable * * @param {string||string[]} id the id of the element, or an array * of ids to look for. * @param {function} fn what to execute when the element is found. * @param {object} p_obj an optional object to be passed back as * a parameter to fn. * @param {boolean|object} p_override If set to true, fn will execute * in the context of p_obj, if set to an object it * will execute in the context of that object * @param checkContent {boolean} check child node readiness (onContentReady) * @static * @deprecated Use Y.on("available") */ // @TODO fix arguments onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) { var a = Y.Array(id), i, availHandle; for (i=0; i* An augmentable class, which provides the augmented class with the ability to host plugins. * It adds plug and unplug methods to the augmented class, which can * be used to add or remove plugins from instances of the class. *
* *Plugins can also be added through the constructor configuration object passed to the host class' constructor using * the "plugins" property. Supported values for the "plugins" property are those defined by the plug method. * * For example the following code would add the AnimPlugin and IOPlugin to Overlay (the plugin host): *
* Plug.Host's protected _initPlugins and _destroyPlugins * methods should be invoked by the host class at the appropriate point in the host's lifecyle. *
* * @class Plugin.Host */ var L = Y.Lang; function PluginHost() { this._plugins = {}; } PluginHost.prototype = { /** * Adds a plugin to the host object. This will instantiate the * plugin and attach it to the configured namespace on the host object. * * @method plug * @chainable * @param P {Function | Object |Array} Accepts the plugin class, or an * object with a "fn" property specifying the plugin class and * a "cfg" property specifying the configuration for the Plugin. ** Additionally an Array can also be passed in, with the above function or * object values, allowing the user to add multiple plugins in a single call. *
* @param config (Optional) If the first argument is the plugin class, the second argument * can be the configuration for the plugin. * @return {Base} A reference to the host object */ plug: function(Plugin, config) { var i, ln, ns; if (L.isArray(Plugin)) { for (i = 0, ln = Plugin.length; i < ln; i++) { this.plug(Plugin[i]); } } else { if (Plugin && !L.isFunction(Plugin)) { config = Plugin.cfg; Plugin = Plugin.fn; } // Plugin should be fn by now if (Plugin && Plugin.NS) { ns = Plugin.NS; config = config || {}; config.host = this; if (this.hasPlugin(ns)) { // Update config this[ns].setAttrs(config); } else { // Create new instance this[ns] = new Plugin(config); this._plugins[ns] = Plugin; } } } return this; }, /** * Removes a plugin from the host object. This will destroy the * plugin instance and delete the namepsace from the host object. * * @method unplug * @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided, * all registered plugins are unplugged. * @return {Base} A reference to the host object * @chainable */ unplug: function(plugin) { var ns = plugin, plugins = this._plugins; if (plugin) { if (L.isFunction(plugin)) { ns = plugin.NS; if (ns && (!plugins[ns] || plugins[ns] !== plugin)) { ns = null; } } if (ns) { if (this[ns]) { this[ns].destroy(); delete this[ns]; } if (plugins[ns]) { delete plugins[ns]; } } } else { for (ns in this._plugins) { if (this._plugins.hasOwnProperty(ns)) { this.unplug(ns); } } } return this; }, /** * Determines if a plugin has plugged into this host. * * @method hasPlugin * @param {String} ns The plugin's namespace * @return {boolean} returns true, if the plugin has been plugged into this host, false otherwise. */ hasPlugin : function(ns) { return (this._plugins[ns] && this[ns]); }, /** * Initializes static plugins registered on the host (using the * Base.plug static method) and any plugins passed to the * instance through the "plugins" configuration property. * * @method _initPlugins * @param {Config} config The configuration object with property name/value pairs. * @private */ _initPlugins: function(config) { this._plugins = this._plugins || {}; if (this._initConfigPlugins) { this._initConfigPlugins(config); } }, /** * Unplugs and destroys all plugins on the host * @method _destroyPlugins * @private */ _destroyPlugins: function() { this.unplug(); } }; Y.namespace("Plugin").Host = PluginHost; }, '3.3.0' ,{requires:['yui-base']}); YUI.add('pluginhost-config', function(Y) { /** * Adds pluginhost constructor configuration and static configuration support * @submodule pluginhost-config */ /** * Constructor and static configuration support for plugins * * @for Plugin.Host */ var PluginHost = Y.Plugin.Host, L = Y.Lang; PluginHost.prototype._initConfigPlugins = function(config) { // Class Configuration var classes = (this._getClasses) ? this._getClasses() : [this.constructor], plug = [], unplug = {}, constructor, i, classPlug, classUnplug, pluginClassName; // TODO: Room for optimization. Can we apply statically/unplug in same pass? for (i = classes.length - 1; i >= 0; i--) { constructor = classes[i]; classUnplug = constructor._UNPLUG; if (classUnplug) { // subclasses over-write Y.mix(unplug, classUnplug, true); } classPlug = constructor._PLUG; if (classPlug) { // subclasses over-write Y.mix(plug, classPlug, true); } } for (pluginClassName in plug) { if (plug.hasOwnProperty(pluginClassName)) { if (!unplug[pluginClassName]) { this.plug(plug[pluginClassName]); } } } // User Configuration if (config && config.plugins) { this.plug(config.plugins); } }; /** * Registers plugins to be instantiated at the class level (plugins * which should be plugged into every instance of the class by default). * * @method Plugin.Host.plug * @static * * @param {Function} hostClass The host class on which to register the plugins * @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined) * @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin */ PluginHost.plug = function(hostClass, plugin, config) { // Cannot plug into Base, since Plugins derive from Base [ will cause infinite recurrsion ] var p, i, l, name; if (hostClass !== Y.Base) { hostClass._PLUG = hostClass._PLUG || {}; if (!L.isArray(plugin)) { if (config) { plugin = {fn:plugin, cfg:config}; } plugin = [plugin]; } for (i = 0, l = plugin.length; i < l;i++) { p = plugin[i]; name = p.NAME || p.fn.NAME; hostClass._PLUG[name] = p; } } }; /** * Unregisters any class level plugins which have been registered by the host class, or any * other class in the hierarchy. * * @method Plugin.Host.unplug * @static * * @param {Function} hostClass The host class from which to unregister the plugins * @param {Function | Array} plugin The plugin class, or an array of plugin classes */ PluginHost.unplug = function(hostClass, plugin) { var p, i, l, name; if (hostClass !== Y.Base) { hostClass._UNPLUG = hostClass._UNPLUG || {}; if (!L.isArray(plugin)) { plugin = [plugin]; } for (i = 0, l = plugin.length; i < l; i++) { p = plugin[i]; name = p.NAME; if (!hostClass._PLUG[name]) { hostClass._UNPLUG[name] = p; } else { delete hostClass._PLUG[name]; } } } }; }, '3.3.0' ,{requires:['pluginhost-base']}); YUI.add('pluginhost', function(Y){}, '3.3.0' ,{use:['pluginhost-base', 'pluginhost-config']}); YUI.add('node-base', function(Y) { /** * The Node Utility provides a DOM-like interface for interacting with DOM nodes. * @module node * @submodule node-base */ /** * The Node class provides a wrapper for manipulating DOM Nodes. * Node properties can be accessed via the set/get methods. * Use Y.get() to retrieve Node instances. * * NOTE: Node properties are accessed using * theset
and get
methods.
*
* @class Node
* @constructor
* @param {DOMNode} node the DOM node to be mapped to the Node instance.
* @for Node
*/
// "globals"
var DOT = '.',
NODE_NAME = 'nodeName',
NODE_TYPE = 'nodeType',
OWNER_DOCUMENT = 'ownerDocument',
TAG_NAME = 'tagName',
UID = '_yuid',
_slice = Array.prototype.slice,
Y_DOM = Y.DOM,
Y_Node = function(node) {
var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID];
if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) {
node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
}
uid = uid || Y.stamp(node);
if (!uid) { // stamp failed; likely IE non-HTMLElement
uid = Y.guid();
}
this[UID] = uid;
/**
* The underlying DOM node bound to the Y.Node instance
* @property _node
* @private
*/
this._node = node;
Y_Node._instances[uid] = this;
this._stateProxy = node; // when augmented with Attribute
Y.EventTarget.call(this, {emitFacade:true});
if (this._initPlugins) { // when augmented with Plugin.Host
this._initPlugins();
}
this.SHOW_TRANSITION = Y_Node.SHOW_TRANSITION;
this.HIDE_TRANSITION = Y_Node.HIDE_TRANSITION;
},
// used with previous/next/ancestor tests
_wrapFn = function(fn) {
var ret = null;
if (fn) {
ret = (typeof fn == 'string') ?
function(n) {
return Y.Selector.test(n, fn);
} :
function(n) {
return fn(Y.one(n));
};
}
return ret;
};
// end "globals"
/**
* The name of the component
* @static
* @property NAME
*/
Y_Node.NAME = 'node';
/*
* The pattern used to identify ARIA attributes
*/
Y_Node.re_aria = /^(?:role$|aria-)/;
Y_Node.SHOW_TRANSITION = 'fadeIn';
Y_Node.HIDE_TRANSITION = 'fadeOut';
/**
* List of events that route to DOM events
* @static
* @property DOM_EVENTS
*/
Y_Node.DOM_EVENTS = {
abort: 1,
beforeunload: 1,
blur: 1,
change: 1,
click: 1,
close: 1,
command: 1,
contextmenu: 1,
dblclick: 1,
DOMMouseScroll: 1,
drag: 1,
dragstart: 1,
dragenter: 1,
dragover: 1,
dragleave: 1,
dragend: 1,
drop: 1,
error: 1,
focus: 1,
key: 1,
keydown: 1,
keypress: 1,
keyup: 1,
load: 1,
message: 1,
mousedown: 1,
mouseenter: 1,
mouseleave: 1,
mousemove: 1,
mousemultiwheel: 1,
mouseout: 1,
mouseover: 1,
mouseup: 1,
mousewheel: 1,
orientationchange: 1,
reset: 1,
resize: 1,
select: 1,
selectstart: 1,
submit: 1,
scroll: 1,
textInput: 1,
unload: 1
};
// Add custom event adaptors to this list. This will make it so
// that delegate, key, available, contentready, etc all will
// be available through Node.on
Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins);
/**
* A list of Node instances that have been created
* @private
* @property _instances
* @static
*
*/
Y_Node._instances = {};
/**
* Retrieves the DOM node bound to a Node instance
* @method getDOMNode
* @static
*
* @param {Y.Node || HTMLNode} node The Node instance or an HTMLNode
* @return {HTMLNode} The DOM node bound to the Node instance. If a DOM node is passed
* as the node argument, it is simply returned.
*/
Y_Node.getDOMNode = function(node) {
if (node) {
return (node.nodeType) ? node : node._node || null;
}
return null;
};
/**
* Checks Node return values and wraps DOM Nodes as Y.Node instances
* and DOM Collections / Arrays as Y.NodeList instances.
* Other return values just pass thru. If undefined is returned (e.g. no return)
* then the Node instance is returned for chainability.
* @method scrubVal
* @static
*
* @param {any} node The Node instance or an HTMLNode
* @return {Y.Node | Y.NodeList | any} Depends on what is returned from the DOM node.
*/
Y_Node.scrubVal = function(val, node) {
if (val) { // only truthy values are risky
if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function
if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window
val = Y.one(val);
} else if ((val.item && !val._nodes) || // dom collection or Node instance
(val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
val = Y.all(val);
}
}
} else if (typeof val === 'undefined') {
val = node; // for chaining
} else if (val === null) {
val = null; // IE: DOM null not the same as null
}
return val;
};
/**
* Adds methods to the Y.Node prototype, routing through scrubVal.
* @method addMethod
* @static
*
* @param {String} name The name of the method to add
* @param {Function} fn The function that becomes the method
* @param {Object} context An optional context to call the method with
* (defaults to the Node instance)
* @return {any} Depends on what is returned from the DOM node.
*/
Y_Node.addMethod = function(name, fn, context) {
if (name && fn && typeof fn == 'function') {
Y_Node.prototype[name] = function() {
var args = _slice.call(arguments),
node = this,
ret;
if (args[0] && Y.instanceOf(args[0], Y_Node)) {
args[0] = args[0]._node;
}
if (args[1] && Y.instanceOf(args[1], Y_Node)) {
args[1] = args[1]._node;
}
args.unshift(node._node);
ret = fn.apply(node, args);
if (ret) { // scrub truthy
ret = Y_Node.scrubVal(ret, node);
}
(typeof ret != 'undefined') || (ret = node);
return ret;
};
} else {
}
};
/**
* Imports utility methods to be added as Y.Node methods.
* @method importMethod
* @static
*
* @param {Object} host The object that contains the method to import.
* @param {String} name The name of the method to import
* @param {String} altName An optional name to use in place of the host name
* @param {Object} context An optional context to call the method with
*/
Y_Node.importMethod = function(host, name, altName) {
if (typeof name == 'string') {
altName = altName || name;
Y_Node.addMethod(altName, host[name], host);
} else {
Y.Array.each(name, function(n) {
Y_Node.importMethod(host, n);
});
}
};
/**
* Returns a single Node instance bound to the node or the
* first element matching the given selector. Returns null if no match found.
* Note: For chaining purposes you may want to
* use Y.all
, which returns a NodeList when no match is found.
* @method Y.one
* @static
* @param {String | HTMLElement} node a node or Selector
* @return {Y.Node | null} a Node instance or null if no match found.
*/
Y_Node.one = function(node) {
var instance = null,
cachedNode,
uid;
if (node) {
if (typeof node == 'string') {
if (node.indexOf('doc') === 0) { // doc OR document
node = Y.config.doc;
} else if (node.indexOf('win') === 0) { // win OR window
node = Y.config.win;
} else {
node = Y.Selector.query(node, null, true);
}
if (!node) {
return null;
}
} else if (Y.instanceOf(node, Y_Node)) {
return node; // NOTE: return
}
if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc)
uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid;
instance = Y_Node._instances[uid]; // reuse exising instances
cachedNode = instance ? instance._node : null;
if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
instance = new Y_Node(node);
}
}
}
return instance;
};
/**
* Returns a new dom node using the provided markup string.
* @method create
* @static
* @param {String} html The markup used to create the element
* @param {HTMLDocument} doc An optional document context
* @return {Node} A Node instance bound to a DOM node or fragment
*/
Y_Node.create = function(html, doc) {
if (doc && doc._node) {
doc = doc._node;
}
return Y.one(Y_DOM.create(html, doc));
};
/**
* Static collection of configuration attributes for special handling
* @property ATTRS
* @static
* @type object
*/
Y_Node.ATTRS = {
/**
* Allows for getting and setting the text of an element.
* Formatting is preserved and special characters are treated literally.
* @config text
* @type String
*/
text: {
getter: function() {
return Y_DOM.getText(this._node);
},
setter: function(content) {
Y_DOM.setText(this._node, content);
return content;
}
},
'options': {
getter: function() {
return this._node.getElementsByTagName('option');
}
},
/**
* Returns a NodeList instance of all HTMLElement children.
* @readOnly
* @config children
* @type NodeList
*/
'children': {
getter: function() {
var node = this._node,
children = node.children,
childNodes, i, len;
if (!children) {
childNodes = node.childNodes;
children = [];
for (i = 0, len = childNodes.length; i < len; ++i) {
if (childNodes[i][TAG_NAME]) {
children[children.length] = childNodes[i];
}
}
}
return Y.all(children);
}
},
value: {
getter: function() {
return Y_DOM.getValue(this._node);
},
setter: function(val) {
Y_DOM.setValue(this._node, val);
return val;
}
}
};
/**
* The default setter for DOM properties
* Called with instance context (this === the Node instance)
* @method DEFAULT_SETTER
* @static
* @param {String} name The attribute/property being set
* @param {any} val The value to be set
* @return {any} The value
*/
Y_Node.DEFAULT_SETTER = function(name, val) {
var node = this._stateProxy,
strPath;
if (name.indexOf(DOT) > -1) {
strPath = name;
name = name.split(DOT);
// only allow when defined on node
Y.Object.setValue(node, name, val);
} else if (typeof node[name] != 'undefined') { // pass thru DOM properties
node[name] = val;
}
return val;
};
/**
* The default getter for DOM properties
* Called with instance context (this === the Node instance)
* @method DEFAULT_GETTER
* @static
* @param {String} name The attribute/property to look up
* @return {any} The current value
*/
Y_Node.DEFAULT_GETTER = function(name) {
var node = this._stateProxy,
val;
if (name.indexOf && name.indexOf(DOT) > -1) {
val = Y.Object.getValue(node, name.split(DOT));
} else if (typeof node[name] != 'undefined') { // pass thru from DOM
val = node[name];
}
return val;
};
// Basic prototype augment - no lazy constructor invocation.
Y.mix(Y_Node, Y.EventTarget, false, null, 1);
Y.mix(Y_Node.prototype, {
/**
* The method called when outputting Node instances as strings
* @method toString
* @return {String} A string representation of the Node instance
*/
toString: function() {
var str = this[UID] + ': not bound to a node',
node = this._node,
attrs, id, className;
if (node) {
attrs = node.attributes;
id = (attrs && attrs.id) ? node.getAttribute('id') : null;
className = (attrs && attrs.className) ? node.getAttribute('className') : null;
str = node[NODE_NAME];
if (id) {
str += '#' + id;
}
if (className) {
str += '.' + className.replace(' ', '.');
}
// TODO: add yuid?
str += ' ' + this[UID];
}
return str;
},
/**
* Returns an attribute value on the Node instance.
* Unless pre-configured (via Node.ATTRS), get hands
* off to the underlying DOM node. Only valid
* attributes/properties for the node will be set.
* @method get
* @param {String} attr The attribute
* @return {any} The current value of the attribute
*/
get: function(attr) {
var val;
if (this._getAttr) { // use Attribute imple
val = this._getAttr(attr);
} else {
val = this._get(attr);
}
if (val) {
val = Y_Node.scrubVal(val, this);
} else if (val === null) {
val = null; // IE: DOM null is not true null (even though they ===)
}
return val;
},
/**
* Helper method for get.
* @method _get
* @private
* @param {String} attr The attribute
* @return {any} The current value of the attribute
*/
_get: function(attr) {
var attrConfig = Y_Node.ATTRS[attr],
val;
if (attrConfig && attrConfig.getter) {
val = attrConfig.getter.call(this);
} else if (Y_Node.re_aria.test(attr)) {
val = this._node.getAttribute(attr, 2);
} else {
val = Y_Node.DEFAULT_GETTER.apply(this, arguments);
}
return val;
},
/**
* Sets an attribute on the Node instance.
* Unless pre-configured (via Node.ATTRS), set hands
* off to the underlying DOM node. Only valid
* attributes/properties for the node will be set.
* To set custom attributes use setAttribute.
* @method set
* @param {String} attr The attribute to be set.
* @param {any} val The value to set the attribute to.
* @chainable
*/
set: function(attr, val) {
var attrConfig = Y_Node.ATTRS[attr];
if (this._setAttr) { // use Attribute imple
this._setAttr.apply(this, arguments);
} else { // use setters inline
if (attrConfig && attrConfig.setter) {
attrConfig.setter.call(this, val, attr);
} else if (Y_Node.re_aria.test(attr)) { // special case Aria
this._node.setAttribute(attr, val);
} else {
Y_Node.DEFAULT_SETTER.apply(this, arguments);
}
}
return this;
},
/**
* Sets multiple attributes.
* @method setAttrs
* @param {Object} attrMap an object of name/value pairs to set
* @chainable
*/
setAttrs: function(attrMap) {
if (this._setAttrs) { // use Attribute imple
this._setAttrs(attrMap);
} else { // use setters inline
Y.Object.each(attrMap, function(v, n) {
this.set(n, v);
}, this);
}
return this;
},
/**
* Returns an object containing the values for the requested attributes.
* @method getAttrs
* @param {Array} attrs an array of attributes to get values
* @return {Object} An object with attribute name/value pairs.
*/
getAttrs: function(attrs) {
var ret = {};
if (this._getAttrs) { // use Attribute imple
this._getAttrs(attrs);
} else { // use setters inline
Y.Array.each(attrs, function(v, n) {
ret[v] = this.get(v);
}, this);
}
return ret;
},
/**
* Creates a new Node using the provided markup string.
* @method create
* @param {String} html The markup used to create the element
* @param {HTMLDocument} doc An optional document context
* @return {Node} A Node instance bound to a DOM node or fragment
*/
create: Y_Node.create,
/**
* Compares nodes to determine if they match.
* Node instances can be compared to each other and/or HTMLElements.
* @method compareTo
* @param {HTMLElement | Node} refNode The reference node to compare to the node.
* @return {Boolean} True if the nodes match, false if they do not.
*/
compareTo: function(refNode) {
var node = this._node;
if (Y.instanceOf(refNode, Y_Node)) {
refNode = refNode._node;
}
return node === refNode;
},
/**
* Determines whether the node is appended to the document.
* @method inDoc
* @param {Node|HTMLElement} doc optional An optional document to check against.
* Defaults to current document.
* @return {Boolean} Whether or not this node is appended to the document.
*/
inDoc: function(doc) {
var node = this._node;
doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
if (doc.documentElement) {
return Y_DOM.contains(doc.documentElement, node);
}
},
getById: function(id) {
var node = this._node,
ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]);
if (ret && Y_DOM.contains(node, ret)) {
ret = Y.one(ret);
} else {
ret = null;
}
return ret;
},
/**
* Returns the nearest ancestor that passes the test applied by supplied boolean method.
* @method ancestor
* @param {String | Function} fn A selector string or boolean method for testing elements.
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
* If a function is used, it receives the current node being tested as the only argument.
* @return {Node} The matching Node instance or null if not found
*/
ancestor: function(fn, testSelf) {
return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf));
},
/**
* Returns the ancestors that pass the test applied by supplied boolean method.
* @method ancestors
* @param {String | Function} fn A selector string or boolean method for testing elements.
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
* If a function is used, it receives the current node being tested as the only argument.
* @return {NodeList} A NodeList instance containing the matching elements
*/
ancestors: function(fn, testSelf) {
return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf));
},
/**
* Returns the previous matching sibling.
* Returns the nearest element node sibling if no method provided.
* @method previous
* @param {String | Function} fn A selector or boolean method for testing elements.
* If a function is used, it receives the current node being tested as the only argument.
* @return {Node} Node instance or null if not found
*/
previous: function(fn, all) {
return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
},
/**
* Returns the next matching sibling.
* Returns the nearest element node sibling if no method provided.
* @method next
* @param {String | Function} fn A selector or boolean method for testing elements.
* If a function is used, it receives the current node being tested as the only argument.
* @return {Node} Node instance or null if not found
*/
next: function(fn, all) {
return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
},
/**
* Returns all matching siblings.
* Returns all siblings if no method provided.
* @method siblings
* @param {String | Function} fn A selector or boolean method for testing elements.
* If a function is used, it receives the current node being tested as the only argument.
* @return {NodeList} NodeList instance bound to found siblings
*/
siblings: function(fn) {
return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn)));
},
/**
* Retrieves a Node instance of nodes based on the given CSS selector.
* @method one
*
* @param {string} selector The CSS selector to test against.
* @return {Node} A Node instance for the matching HTMLElement.
*/
one: function(selector) {
return Y.one(Y.Selector.query(selector, this._node, true));
},
/**
* Retrieves a nodeList based on the given CSS selector.
* @method all
*
* @param {string} selector The CSS selector to test against.
* @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
*/
all: function(selector) {
var nodelist = Y.all(Y.Selector.query(selector, this._node));
nodelist._query = selector;
nodelist._queryRoot = this._node;
return nodelist;
},
// TODO: allow fn test
/**
* Test if the supplied node matches the supplied selector.
* @method test
*
* @param {string} selector The CSS selector to test against.
* @return {boolean} Whether or not the node matches the selector.
*/
test: function(selector) {
return Y.Selector.test(this._node, selector);
},
/**
* Removes the node from its parent.
* Shortcut for myNode.get('parentNode').removeChild(myNode);
* @method remove
* @param {Boolean} destroy whether or not to call destroy() on the node
* after removal.
* @chainable
*
*/
remove: function(destroy) {
var node = this._node,
parentNode = node.parentNode;
if (parentNode) {
parentNode.removeChild(node);
}
if (destroy) {
this.destroy();
}
return this;
},
/**
* Replace the node with the other node. This is a DOM update only
* and does not change the node bound to the Node instance.
* Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
* @method replace
* @param {Y.Node || HTMLNode} newNode Node to be inserted
* @chainable
*
*/
replace: function(newNode) {
var node = this._node;
if (typeof newNode == 'string') {
newNode = Y_Node.create(newNode);
}
node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node);
return this;
},
/**
* @method replaceChild
* @for Node
* @param {String | HTMLElement | Node} node Node to be inserted
* @param {HTMLElement | Node} refNode Node to be replaced
* @return {Node} The replaced node
*/
replaceChild: function(node, refNode) {
if (typeof node == 'string') {
node = Y_DOM.create(node);
}
return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode)));
},
/**
* @method appendChild
* @param {String | HTMLElement | Node} node Node to be appended
* @return {Node} The appended node
*/
appendChild: function(node) {
return Y_Node.scrubVal(this._insert(node));
},
/**
* @method insertBefore
* @param {String | HTMLElement | Node} newNode Node to be appended
* @param {HTMLElement | Node} refNode Node to be inserted before
* @return {Node} The inserted node
*/
insertBefore: function(newNode, refNode) {
return Y.Node.scrubVal(this._insert(newNode, refNode));
},
/**
* Removes event listeners from the node and (optionally) its subtree
* @method purge
* @param {Boolean} recurse (optional) Whether or not to remove listeners from the
* node's subtree
* @param {String} type (optional) Only remove listeners of the specified type
* @chainable
*
*/
purge: function(recurse, type) {
Y.Event.purgeElement(this._node, recurse, type);
return this;
},
/**
* Nulls internal node references, removes any plugins and event listeners
* @method destroy
* @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the
* node's subtree (default is false)
*
*/
destroy: function(recursive) {
this.purge(); // TODO: only remove events add via this Node
if (this.unplug) { // may not be a PluginHost
this.unplug();
}
this.clearData();
if (recursive) {
this.all('*').destroy();
}
this._node = null;
this._stateProxy = null;
delete Y_Node._instances[this[UID]];
},
/**
* Invokes a method on the Node instance
* @method invoke
* @param {String} method The name of the method to invoke
* @param {Any} a, b, c, etc. Arguments to invoke the method with.
* @return Whatever the underly method returns.
* DOM Nodes and Collections return values
* are converted to Node/NodeList instances.
*
*/
invoke: function(method, a, b, c, d, e) {
var node = this._node,
ret;
if (a && Y.instanceOf(a, Y_Node)) {
a = a._node;
}
if (b && Y.instanceOf(b, Y_Node)) {
b = b._node;
}
ret = node[method](a, b, c, d, e);
return Y_Node.scrubVal(ret, this);
},
/**
* Inserts the content before the reference node.
* @method insert
* @param {String | Y.Node | HTMLElement | Y.NodeList | HTMLCollection} content The content to insert
* @param {Int | Y.Node | HTMLElement | String} where The position to insert at.
* Possible "where" arguments
* Sets up a delegation listener for an event occurring inside the Node. * The delegated event will be verified against a supplied selector or * filtering function to test if the event references at least one node that * should trigger the subscription callback.
* *Selector string filters will trigger the callback if the event originated * from a node that matches it or is contained in a node that matches it. * Function filters are called for each Node up the parent axis to the * subscribing container node, and receive at each level the Node and the event * object. The function should return true (or a truthy value) if that Node * should trigger the subscription callback. Note, it is possible for filters * to match multiple Nodes for a single event. In this case, the delegate * callback will be executed for each matching Node.
* *For each matching Node, the callback will be executed with its 'this'
* object set to the Node matched by the filter (unless a specific context was
* provided during subscription), and the provided event's
* currentTarget
will also be set to the matching Node. The
* containing Node from which the subscription was originally made can be
* referenced as e.container
.
*
* @method delegate
* @param type {String} the event type to delegate
* @param fn {Function} the callback function to execute. This function
* will be provided the event object for the delegated event.
* @param spec {String|Function} a selector that must match the target of the
* event or a function to test target and its parents for a match
* @param context {Object} optional argument that specifies what 'this' refers to.
* @param args* {any} 0..n additional arguments to pass on to the callback function.
* These arguments will be added after the event object.
* @return {EventHandle} the detach handle
* @for Node
*/
Y.Node.prototype.delegate = function(type) {
var args = Y.Array(arguments, 0, true),
index = (Y.Lang.isObject(type) && !Y.Lang.isArray(type)) ? 1 : 2;
args.splice(index, 0, this._node);
return Y.delegate.apply(Y, args);
};
}, '3.3.0' ,{requires:['node-base', 'event-delegate']});
YUI.add('node', function(Y){}, '3.3.0' ,{skinnable:false, requires:['dom', 'event-base', 'event-delegate', 'pluginhost'], use:['node-base', 'node-style', 'node-screen', 'node-pluginhost', 'node-event-delegate']});
YUI.add('event-delegate', function(Y) {
/**
* Adds event delegation support to the library.
*
* @module event
* @submodule event-delegate
*/
var toArray = Y.Array,
YLang = Y.Lang,
isString = YLang.isString,
isObject = YLang.isObject,
isArray = YLang.isArray,
selectorTest = Y.Selector.test,
detachCategories = Y.Env.evt.handles;
/**
*
Sets up event delegation on a container element. The delegated event * will use a supplied selector or filtering function to test if the event * references at least one node that should trigger the subscription * callback.
* *Selector string filters will trigger the callback if the event originated * from a node that matches it or is contained in a node that matches it. * Function filters are called for each Node up the parent axis to the * subscribing container node, and receive at each level the Node and the event * object. The function should return true (or a truthy value) if that Node * should trigger the subscription callback. Note, it is possible for filters * to match multiple Nodes for a single event. In this case, the delegate * callback will be executed for each matching Node.
* *For each matching Node, the callback will be executed with its 'this'
* object set to the Node matched by the filter (unless a specific context was
* provided during subscription), and the provided event's
* currentTarget
will also be set to the matching Node. The
* containing Node from which the subscription was originally made can be
* referenced as e.container
.
*
* @method delegate
* @param type {String} the event type to delegate
* @param fn {Function} the callback function to execute. This function
* will be provided the event object for the delegated event.
* @param el {String|node} the element that is the delegation container
* @param spec {string|Function} a selector that must match the target of the
* event or a function to test target and its parents for a match
* @param context optional argument that specifies what 'this' refers to.
* @param args* 0..n additional arguments to pass on to the callback function.
* These arguments will be added after the event object.
* @return {EventHandle} the detach handle
* @for YUI
*/
function delegate(type, fn, el, filter) {
var args = toArray(arguments, 0, true),
query = isString(el) ? el : null,
typeBits, synth, container, categories, cat, i, len, handles, handle;
// Support Y.delegate({ click: fnA, key: fnB }, context, filter, ...);
// and Y.delegate(['click', 'key'], fn, context, filter, ...);
if (isObject(type)) {
handles = [];
if (isArray(type)) {
for (i = 0, len = type.length; i < len; ++i) {
args[0] = type[i];
handles.push(Y.delegate.apply(Y, args));
}
} else {
// Y.delegate({'click', fn}, context, filter) =>
// Y.delegate('click', fn, context, filter)
args.unshift(null); // one arg becomes two; need to make space
for (i in type) {
if (type.hasOwnProperty(i)) {
args[0] = i;
args[1] = type[i];
handles.push(Y.delegate.apply(Y, args));
}
}
}
return new Y.EventHandle(handles);
}
typeBits = type.split(/\|/);
if (typeBits.length > 1) {
cat = typeBits.shift();
type = typeBits.shift();
}
synth = Y.Node.DOM_EVENTS[type];
if (isObject(synth) && synth.delegate) {
handle = synth.delegate.apply(synth, arguments);
}
if (!handle) {
if (!type || !fn || !el || !filter) {
return;
}
container = (query) ? Y.Selector.query(query, null, true) : el;
if (!container && isString(el)) {
handle = Y.on('available', function () {
Y.mix(handle, Y.delegate.apply(Y, args), true);
}, el);
}
if (!handle && container) {
args.splice(2, 2, container); // remove the filter
handle = Y.Event._attach(args, { facade: false });
handle.sub.filter = filter;
handle.sub._notify = delegate.notifySub;
}
}
if (handle && cat) {
categories = detachCategories[cat] || (detachCategories[cat] = {});
categories = categories[type] || (categories[type] = []);
categories.push(handle);
}
return handle;
}
/**
* Overrides the _notify
method on the normal DOM subscription to
* inject the filtering logic and only proceed in the case of a match.
*
* @method delegate.notifySub
* @param thisObj {Object} default 'this' object for the callback
* @param args {Array} arguments passed to the event's fire()
* @param ce {CustomEvent} the custom event managing the DOM subscriptions for
* the subscribed event on the subscribing node.
* @return {Boolean} false if the event was stopped
* @private
* @static
* @since 3.2.0
*/
delegate.notifySub = function (thisObj, args, ce) {
// Preserve args for other subscribers
args = args.slice();
if (this.args) {
args.push.apply(args, this.args);
}
// Only notify subs if the event occurred on a targeted element
var currentTarget = delegate._applyFilter(this.filter, args, ce),
//container = e.currentTarget,
e, i, len, ret;
if (currentTarget) {
// Support multiple matches up the the container subtree
currentTarget = toArray(currentTarget);
// The second arg is the currentTarget, but we'll be reusing this
// facade, replacing the currentTarget for each use, so it doesn't
// matter what element we seed it with.
e = args[0] = new Y.DOMEventFacade(args[0], ce.el, ce);
e.container = Y.one(ce.el);
for (i = 0, len = currentTarget.length; i < len && !e.stopped; ++i) {
e.currentTarget = Y.one(currentTarget[i]);
ret = this.fn.apply(this.context || e.currentTarget, args);
if (ret === false) { // stop further notifications
break;
}
}
return ret;
}
};
/**
*
Compiles a selector string into a filter function to identify whether * Nodes along the parent axis of an event's target should trigger event * notification.
* *This function is memoized, so previously compiled filter functions are * returned if the same selector string is provided.
* *This function may be useful when defining synthetic events for delegate * handling.
* * @method delegate.compileFilter * @param selector {String} the selector string to base the filtration on * @return {Function} * @since 3.2.0 * @static */ delegate.compileFilter = Y.cached(function (selector) { return function (target, e) { return selectorTest(target._node, selector, e.currentTarget._node); }; }); /** * Walks up the parent axis of an event's target, and tests each element * against a supplied filter function. If any Nodes, including the container, * satisfy the filter, the delegated callback will be triggered for each. * * @method delegate._applyFilter * @param filter {Function} boolean function to test for inclusion in event * notification * @param args {Array} the arguments that would be passed to subscribers * @param ce {CustomEvent} the DOM event wrapper * @return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter * @protected */ delegate._applyFilter = function (filter, args, ce) { var e = args[0], container = ce.el, // facadeless events in IE, have no e.currentTarget target = e.target || e.srcElement, match = [], isContainer = false; // Resolve text nodes to their containing element if (target.nodeType === 3) { target = target.parentNode; } // passing target as the first arg rather than leaving well enough alone // making 'this' in the filter function refer to the target. This is to // support bound filter functions. args.unshift(target); if (isString(filter)) { while (target) { isContainer = (target === container); if (selectorTest(target, filter, (isContainer ?null: container))) { match.push(target); } if (isContainer) { break; } target = target.parentNode; } } else { // filter functions are implementer code and should receive wrappers args[0] = Y.one(target); args[1] = new Y.DOMEventFacade(e, container, ce); while (target) { // filter(target, e, extra args...) - this === target if (filter.apply(args[0], args)) { match.push(target); } if (target === container) { break; } target = target.parentNode; args[0] = Y.one(target); } args[1] = e; // restore the raw DOM event } if (match.length <= 1) { match = match[0]; // single match or undefined } // remove the target args.shift(); return match; }; /** * Sets up event delegation on a container element. The delegated event * will use a supplied filter to test if the callback should be executed. * This filter can be either a selector string or a function that returns * a Node to use as the currentTarget for the event. * * The event object for the delegated event is supplied to the callback * function. It is modified slightly in order to support all properties * that may be needed for event delegation. 'currentTarget' is set to * the element that matched the selector string filter or the Node returned * from the filter function. 'container' is set to the element that the * listener is delegated from (this normally would be the 'currentTarget'). * * Filter functions will be called with the arguments that would be passed to * the callback function, including the event object as the first parameter. * The function should return false (or a falsey value) if the success criteria * aren't met, and the Node to use as the event's currentTarget and 'this' * object if they are. * * @method delegate * @param type {string} the event type to delegate * @param fn {function} the callback function to execute. This function * will be provided the event object for the delegated event. * @param el {string|node} the element that is the delegation container * @param filter {string|function} a selector that must match the target of the * event or a function that returns a Node or false. * @param context optional argument that specifies what 'this' refers to. * @param args* 0..n additional arguments to pass on to the callback function. * These arguments will be added after the event object. * @return {EventHandle} the detach handle * @for YUI */ Y.delegate = Y.Event.delegate = delegate; }, '3.3.0' ,{requires:['node-base']}); YUI.add('io-base', function(Y) { /** * Base IO functionality. Provides basic XHR transport support. * @module io * @submodule io-base */ /** * The io class is a utility that brokers HTTP requests through a simplified * interface. Specifically, it allows JavaScript to make HTTP requests to * a resource without a page reload. The underlying transport for making * same-domain requests is the XMLHttpRequest object. YUI.io can also use * Flash, if specified as a transport, for cross-domain requests. * * @class io */ /** * @event io:start * @description This event is fired by YUI.io when a transaction is initiated. * @type Event Custom */ var E_START = 'io:start', /** * @event io:complete * @description This event is fired by YUI.io when a transaction is complete. * Response status and data are accessible, if available. * @type Event Custom */ E_COMPLETE = 'io:complete', /** * @event io:success * @description This event is fired by YUI.io when a transaction is complete, and * the HTTP status resolves to HTTP2xx. * @type Event Custom */ E_SUCCESS = 'io:success', /** * @event io:failure * @description This event is fired by YUI.io when a transaction is complete, and * the HTTP status resolves to HTTP4xx, 5xx and above. * @type Event Custom */ E_FAILURE = 'io:failure', /** * @event io:end * @description This event signifies the end of the transaction lifecycle. The * transaction transport is destroyed. * @type Event Custom */ E_END = 'io:end', //-------------------------------------- // Properties //-------------------------------------- /** * @description A transaction counter that increments for each transaction. * * @property transactionId * @private * @static * @type int */ transactionId = 0, /** * @description Object of default HTTP headers to be initialized and sent * for all transactions. * * @property _headers * @private * @static * @type object */ _headers = { 'X-Requested-With' : 'XMLHttpRequest' }, /** * @description Object that stores timeout values for any transaction with * a defined "timeout" configuration property. * * @property _timeout * @private * @static * @type object */ _timeout = {}, // Window reference w = Y.config.win; //-------------------------------------- // Methods //-------------------------------------- /** * @description Method that creates the XMLHttpRequest transport * * @method _xhr * @private * @static * @return object */ function _xhr() { return w.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); } /** * @description Method that increments _transactionId for each transaction. * * @method _id * @private * @static * @return int */ function _id() { var id = transactionId; transactionId++; return id; } /** * @description Method that creates a unique transaction object for each * request. * * @method _create * @private * @static * @param {number} c - configuration object subset to determine if * the transaction is an XDR or file upload, * requiring an alternate transport. * @param {number} i - transaction id * @return object */ function _create(c, i) { var o = {}; o.id = Y.Lang.isNumber(i) ? i : _id(); c = c || {}; if (!c.use && !c.upload) { o.c = _xhr(); } else if (c.use) { if (c.use === 'native') { if (w.XDomainRequest) { o.c = new XDomainRequest(); o.t = c.use; } else { o.c = _xhr(); } } else { o.c = Y.io._transport[c.use]; o.t = c.use; } } else { o.c = {}; } return o; } function _destroy(o) { if (w) { if (o.c && w.XMLHttpRequest) { o.c.onreadystatechange = null; } else if (Y.UA.ie === 6 && !o.t) { // IE, when using XMLHttpRequest as an ActiveX Object, will throw // a "Type Mismatch" error if the event handler is set to "null". o.c.abort(); } } o.c = null; o = null; } /** * @description Method for creating and subscribing transaction events. * * @method _tE * @private * @static * @param {string} e - event to be published * @param {object} c - configuration data subset for event subscription. * * @return void */ function _tE(e, c) { var eT = new Y.EventTarget().publish('transaction:' + e), a = c.arguments, cT = c.context || Y; if (a) { eT.on(c.on[e], cT, a); } else { eT.on(c.on[e], cT); } return eT; } /** * @description Fires event "io:start" and creates, fires a * transaction-specific start event, if config.on.start is * defined. * * @method _ioStart * @private * @static * @param {number} id - transaction id * @param {object} c - configuration object for the transaction. * * @return void */ function _ioStart(id, c) { var a = c.arguments; if (a) { Y.fire(E_START, id, a); } else { Y.fire(E_START, id); } if (c.on && c.on.start) { _tE('start', c).fire(id); } } /** * @description Fires event "io:complete" and creates, fires a * transaction-specific "complete" event, if config.on.complete is * defined. * * @method _ioComplete * @private * @static * @param {object} o - transaction object. * @param {object} c - configuration object for the transaction. * * @return void */ function _ioComplete(o, c) { var r = o.e ? { status: 0, statusText: o.e } : o.c, a = c.arguments; if (a) { Y.fire(E_COMPLETE, o.id, r, a); } else { Y.fire(E_COMPLETE, o.id, r); } if (c.on && c.on.complete) { _tE('complete', c).fire(o.id, r); } } /** * @description Fires event "io:end" and creates, fires a * transaction-specific "end" event, if config.on.end is * defined. * * @method _ioEnd * @private * @static * @param {object} o - transaction object. * @param {object} c - configuration object for the transaction. * * @return void */ function _ioEnd(o, c) { var a = c.arguments; if (a) { Y.fire(E_END, o.id, a); } else { Y.fire(E_END, o.id); } if (c.on && c.on.end) { _tE('end', c).fire(o.id); } _destroy(o); } /** * @description Fires event "io:success" and creates, fires a * transaction-specific "success" event, if config.on.success is * defined. * * @method _ioSuccess * @private * @static * @param {object} o - transaction object. * @param {object} c - configuration object for the transaction. * * @return void */ function _ioSuccess(o, c) { var a = c.arguments; if (a) { Y.fire(E_SUCCESS, o.id, o.c, a); } else { Y.fire(E_SUCCESS, o.id, o.c); } if (c.on && c.on.success) { _tE('success', c).fire(o.id, o.c); } _ioEnd(o, c); } /** * @description Fires event "io:failure" and creates, fires a * transaction-specific "failure" event, if config.on.failure is * defined. * * @method _ioFailure * @private * @static * @param {object} o - transaction object. * @param {object} c - configuration object for the transaction. * * @return void */ function _ioFailure(o, c) { var r = o.e ? { status: 0, statusText: o.e } : o.c, a = c.arguments; if (a) { Y.fire(E_FAILURE, o.id, r, a); } else { Y.fire(E_FAILURE, o.id, r); } if (c.on && c.on.failure) { _tE('failure', c).fire(o.id, r); } _ioEnd(o, c); } /** * @description Resends an XDR transaction, using the Flash tranport, * if the native transport fails. * * @method _resend * @private * @static * @param {object} o - Transaction object generated by _create(). * @param {string} uri - qualified path to transaction resource. * @param {object} c - configuration object for the transaction. * * @return void */ function _resend(o, uri, c, d) { _destroy(o); c.xdr.use = 'flash'; // If the original request included serialized form data and // additional data are defined in configuration.data, it must // be reset to prevent data duplication. c.data = c.form && d ? d : null; return Y.io(uri, c, o.id); } /** * @description Method that concatenates string data for HTTP GET transactions. * * @method _concat * @private * @static * @param {string} s - URI or root data. * @param {string} d - data to be concatenated onto URI. * @return int */ function _concat(s, d) { s += ((s.indexOf('?') == -1) ? '?' : '&') + d; return s; } /** * @description Method that stores default client headers for all transactions. * If a label is passed with no value argument, the header will be deleted. * * @method _setHeader * @private * @static * @param {string} l - HTTP header * @param {string} v - HTTP header value * @return int */ function _setHeader(l, v) { if (v) { _headers[l] = v; } else { delete _headers[l]; } } /** * @description Method that sets all HTTP headers to be sent in a transaction. * * @method _setHeaders * @private * @static * @param {object} o - XHR instance for the specific transaction. * @param {object} h - HTTP headers for the specific transaction, as defined * in the configuration object passed to YUI.io(). * @return void */ function _setHeaders(o, h) { var p; h = h || {}; for (p in _headers) { if (_headers.hasOwnProperty(p)) { /* if (h[p]) { // Configuration headers will supersede preset io headers, // if headers match. continue; } else { h[p] = _headers[p]; } */ if (!h[p]) { h[p] = _headers[p]; } } } for (p in h) { if (h.hasOwnProperty(p)) { if (h[p] !== 'disable') { o.setRequestHeader(p, h[p]); } } } } /** * @description Terminates a transaction due to an explicit abort or * timeout. * * @method _ioCancel * @private * @static * @param {object} o - Transaction object generated by _create(). * @param {string} s - Identifies timed out or aborted transaction. * * @return void */ function _ioCancel(o, s) { if (o && o.c) { o.e = s; o.c.abort(); } } /** * @description Starts timeout count if the configuration object * has a defined timeout property. * * @method _startTimeout * @private * @static * @param {object} o - Transaction object generated by _create(). * @param {object} t - Timeout in milliseconds. * @return void */ function _startTimeout(o, t) { _timeout[o.id] = w.setTimeout(function() { _ioCancel(o, 'timeout'); }, t); } /** * @description Clears the timeout interval started by _startTimeout(). * * @method _clearTimeout * @private * @static * @param {number} id - Transaction id. * @return void */ function _clearTimeout(id) { w.clearTimeout(_timeout[id]); delete _timeout[id]; } /** * @description Method that determines if a transaction response qualifies * as success or failure, based on the response HTTP status code, and * fires the appropriate success or failure events. * * @method _handleResponse * @private * @static * @param {object} o - Transaction object generated by _create(). * @param {object} c - Configuration object passed to io(). * @return void */ function _handleResponse(o, c) { var status; try { status = (o.c.status && o.c.status !== 0) ? o.c.status : 0; } catch(e) { status = 0; } // IE reports HTTP 204 as HTTP 1223. if (status >= 200 && status < 300 || status === 1223) { _ioSuccess(o, c); } else { _ioFailure(o, c); } } /** * @description Event handler bound to onreadystatechange. * * @method _readyState * @private * @static * @param {object} o - Transaction object generated by _create(). * @param {object} c - Configuration object passed to YUI.io(). * @return void */ function _readyState(o, c) { if (o.c.readyState === 4) { if (c.timeout) { _clearTimeout(o.id); } w.setTimeout( function() { _ioComplete(o, c); _handleResponse(o, c); }, 0); } } /** * @description Method for requesting a transaction. _io() is implemented as * yui.io(). Each transaction may include a configuration object. Its * properties are: * * method: HTTP method verb (e.g., GET or POST). If this property is not * not defined, the default value will be GET. * * data: This is the name-value string that will be sent as the transaction * data. If the request is HTTP GET, the data become part of * querystring. If HTTP POST, the data are sent in the message body. * * xdr: Defines the transport to be used for cross-domain requests. By * setting this property, the transaction will use the specified * transport instead of XMLHttpRequest. * The properties are: * { * use: Specify the transport to be used: 'flash' and 'native' * dataType: Set the value to 'XML' if that is the expected * response content type. * } * * * form: This is a defined object used to process HTML form as data. The * properties are: * { * id: Node object or id of HTML form. * useDisabled: Boolean value to allow disabled HTML form field * values to be sent as part of the data. * } * * on: This is a defined object used to create and handle specific * events during a transaction lifecycle. These events will fire in * addition to the global io events. The events are: * start - This event is fired when a request is sent to a resource. * complete - This event fires when the transaction is complete. * success - This event fires when the response status resolves to * HTTP 2xx. * failure - This event fires when the response status resolves to * HTTP 4xx, 5xx; and, for all transaction exceptions, * including aborted transactions and transaction timeouts. * end - This even is fired at the conclusion of the transaction * lifecycle, after a success or failure resolution. * * The properties are: * { * start: function(id, arguments){}, * complete: function(id, responseobject, arguments){}, * success: function(id, responseobject, arguments){}, * failure: function(id, responseobject, arguments){}, * end: function(id, arguments){} * } * Each property can reference a function or be written as an * inline function. * * sync: To enable synchronous transactions, set the configuration property * "sync" to true; the default behavior is false. Synchronous * transactions are limited to same-domain requests only. * * context: Object reference for all defined transaction event handlers * when it is implemented as a method of a base object. Defining * "context" will set the reference of "this," used in the * event handlers, to the context value. In the case where * different event handlers all have different contexts, * use Y.bind() to set the execution context, bypassing this * configuration. * * headers: This is a defined object of client headers, as many as. * desired for the transaction. The object pattern is: * { 'header': 'value' }. * * timeout: This value, defined as milliseconds, is a time threshold for the * transaction. When this threshold is reached, and the transaction's * Complete event has not yet fired, the transaction will be aborted. * * arguments: Object, array, string, or number passed to all registered * event handlers. This value is available as the second * argument in the "start" and "abort" event handlers; and, it is * the third argument in the "complete", "success", and "failure" * event handlers. * * @method _io * @private * @static * @param {string} uri - qualified path to transaction resource. * @param {object} c - configuration object for the transaction. * @param {number} i - transaction id, if already set. * @return object */ function _io(uri, c, i) { var f, o, d, m, r, s, oD, a, j, u = uri; c = Y.Object(c); o = _create(c.xdr || c.form, i); m = c.method ? c.method = c.method.toUpperCase() : c.method = 'GET'; s = c.sync; oD = c.data; //To serialize an object into a key-value string, add the //QueryString module to the YUI instance's 'use' method. if (Y.Lang.isObject(c.data) && Y.QueryString) { c.data = Y.QueryString.stringify(c.data); } if (c.form) { if (c.form.upload) { // This is a file upload transaction, calling // upload() in io-upload-iframe. return Y.io.upload(o, uri, c); } else { // Serialize HTML form data. f = Y.io._serialize(c.form, c.data); if (m === 'POST' || m === 'PUT') { c.data = f; } else if (m === 'GET') { uri = _concat(uri, f); } } } if (c.data && m === 'GET') { uri = _concat(uri, c.data); } if (c.data && m === 'POST') { c.headers = Y.merge({ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, c.headers); } if (o.t) { return Y.io.xdr(uri, o, c); } if (!s) { o.c.onreadystatechange = function() { _readyState(o, c); }; } try { o.c.open(m, uri, s ? false : true); // Will work only in browsers that implement the // Cross-Origin Resource Sharing draft. if (c.xdr && c.xdr.credentials) { o.c.withCredentials = true; } } catch(e1) { if (c.xdr) { // This exception is usually thrown by browsers // that do not support native XDR transactions. return _resend(o, u, c, oD); } } _setHeaders(o.c, c.headers); _ioStart(o.id, c); try { // Using "null" with HTTP POST will result in a request // with no Content-Length header defined. o.c.send(c.data || ''); if (s) { d = o.c; a = ['status', 'statusText', 'responseText', 'responseXML']; r = c.arguments ? { id: o.id, arguments: c.arguments } : { id: o.id }; for (j = 0; j < 4; j++) { r[a[j]] = o.c[a[j]]; } r.getAllResponseHeaders = function() { return d.getAllResponseHeaders(); }; r.getResponseHeader = function(h) { return d.getResponseHeader(h); }; _ioComplete(o, c); _handleResponse(o, c); return r; } } catch(e2) { if (c.xdr) { // This exception is usually thrown by browsers // that do not support native XDR transactions. return _resend(o, u, c, oD); } } // If config.timeout is defined, and the request is standard XHR, // initialize timeout polling. if (c.timeout) { _startTimeout(o, c.timeout); } return { id: o.id, abort: function() { return o.c ? _ioCancel(o, 'abort') : false; }, isInProgress: function() { return o.c ? o.c.readyState !== 4 && o.c.readyState !== 0 : false; } }; } _io.start = _ioStart; _io.complete = _ioComplete; _io.success = _ioSuccess; _io.failure = _ioFailure; _io.end = _ioEnd; _io._id = _id; _io._timeout = _timeout; //-------------------------------------- // Begin public interface definition //-------------------------------------- /** * @description Method that stores default client headers for all transactions. * If a label is passed with no value argument, the header will be deleted. * This is the interface for _setHeader(). * * @method header * @public * @static * @param {string} l - HTTP header * @param {string} v - HTTP header value * @return int */ _io.header = _setHeader; /** * @description Method for requesting a transaction. This * is the interface for _io(). * * @method io * @public * @static * @param {string} uri - qualified path to transaction resource. * @param {object} c - configuration object for the transaction. * @return object */ Y.io = _io; Y.io.http = _io; }, '3.3.0' ,{requires:['event-custom-base', 'querystring-stringify-simple']}); YUI.add('querystring-stringify-simple', function(Y) { /*global Y */ /** *Provides Y.QueryString.stringify method for converting objects to Query Strings. * This is a subset implementation of the full querystring-stringify.
*This module provides the bare minimum functionality (encoding a hash of simple values), * without the additional support for nested data structures. Every key-value pair is * encoded by encodeURIComponent.
*This module provides a minimalistic way for io to handle single-level objects * as transaction data.
* * @module querystring * @submodule querystring-stringify-simple * @for QueryString * @static */ var QueryString = Y.namespace("QueryString"), EUC = encodeURIComponent; /** *Converts a simple object to a Query String representation.
*Nested objects, Arrays, and so on, are not supported.
* * @method stringify * @for QueryString * @public * @submodule querystring-stringify-simple * @param obj {Object} A single-level object to convert to a querystring. * @param cfg {Object} (optional) Configuration object. In the simple * module, only the arrayKey setting is * supported. When set to true, the key of an * array will have the '[]' notation appended * to the key;. * @static */ QueryString.stringify = function (obj, c) { var qs = [], // Default behavior is false; standard key notation. s = c && c.arrayKey ? true : false, key, i, l; for (key in obj) { if (obj.hasOwnProperty(key)) { if (Y.Lang.isArray(obj[key])) { for (i = 0, l = obj[key].length; i < l; i++) { qs.push(EUC(s ? key + '[]' : key) + '=' + EUC(obj[key][i])); } } else { qs.push(EUC(key) + '=' + EUC(obj[key])); } } } return qs.join('&'); }; }, '3.3.0' ); YUI.add('json-parse', function(Y) { /** *The JSON module adds support for serializing JavaScript objects into * JSON strings and parsing JavaScript objects from strings in JSON format.
* *The JSON namespace is added to your YUI instance including static methods * Y.JSON.parse(..) and Y.JSON.stringify(..).
* *The functionality and method signatures follow the ECMAScript 5 * specification. In browsers with native JSON support, the native * implementation is used.
* *The json
module is a rollup of json-parse
and
* json-stringify
.
As their names suggest, json-parse
adds support for parsing
* JSON data (Y.JSON.parse) and json-stringify
for serializing
* JavaScript data into JSON strings (Y.JSON.stringify). You may choose to
* include either of the submodules individually if you don't need the
* complementary functionality, or include the rollup for both.
example usage: * Y.one('#demo').transition({ * duration: 1, // in seconds, default is 0.5 * easing: 'ease-out', // default is 'ease' * delay: '1', // delay start for 1 second, default is 0 * * height: '10px', * width: '10px', * * opacity: { // per property * value: 0, * duration: 2, * delay: 2, * easing: 'ease-in' * } * }); ** @for Node * @method transition * @param {Object} config An object containing one or more style properties, a duration and an easing. * @param {Function} callback A function to run after the transition has completed. * @chainable */ Y.Node.prototype.transition = function(name, config, callback) { var transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)], anim = (transitionAttrs) ? transitionAttrs.transition || null : null, fxConfig, prop; if (typeof name === 'string') { // named effect, pull config from registry if (typeof config === 'function') { callback = config; config = null; } fxConfig = Transition.fx[name]; if (config && typeof config !== 'boolean') { config = Y.clone(config); for (prop in fxConfig) { if (fxConfig.hasOwnProperty(prop)) { if (! (prop in config)) { config[prop] = fxConfig[prop]; } } } } else { config = fxConfig; } } else { // name is a config, config is a callback or undefined callback = config; config = name; } if (anim && !anim._running) { anim.init(this, config); } else { anim = new Transition(this._node, config); } anim.run(callback); return this; }; Y.Node.prototype.show = function(name, config, callback) { this._show(); // show prior to transition if (name && Y.Transition) { if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default if (typeof config === 'function') { callback = config; config = name; } name = this.SHOW_TRANSITION; } this.transition(name, config, callback); } return this; }; var _wrapCallBack = function(anim, fn, callback) { return function() { if (fn) { fn.call(anim); } if (callback) { callback.apply(anim._node, arguments); } }; }; Y.Node.prototype.hide = function(name, config, callback) { if (name && Y.Transition) { if (typeof config === 'function') { callback = config; config = null; } callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default if (typeof config === 'function') { callback = config; config = name; } name = this.HIDE_TRANSITION; } this.transition(name, config, callback); } else { this._hide(); } return this; }; /** * Animate one or more css properties to a given value. Requires the "transition" module. *
example usage: * Y.all('.demo').transition({ * duration: 1, // in seconds, default is 0.5 * easing: 'ease-out', // default is 'ease' * delay: '1', // delay start for 1 second, default is 0 * * height: '10px', * width: '10px', * * opacity: { // per property * value: 0, * duration: 2, * delay: 2, * easing: 'ease-in' * } * }); ** @for NodeList * @method transition * @param {Object} config An object containing one or more style properties, a duration and an easing. * @param {Function} callback A function to run after the transition has completed. The callback fires * once per item in the NodeList. * @chainable */ Y.NodeList.prototype.transition = function(config, callback) { var nodes = this._nodes, i = 0, node; while ((node = nodes[i++])) { Y.one(node).transition(config, callback); } return this; }; Y.Node.prototype.toggleView = function(name, on) { var callback; this._toggles = this._toggles || []; if (typeof name == 'boolean') { // no transition, just toggle on = name; } if (typeof on === 'undefined' && name in this._toggles) { on = ! this._toggles[name]; } on = (on) ? 1 : 0; if (on) { this._show(); } else { callback = _wrapCallBack(anim, this._hide); } this._toggles[name] = on; this.transition(Y.Transition.toggles[name][on], callback); }; Y.NodeList.prototype.toggleView = function(config, callback) { var nodes = this._nodes, i = 0, node; while ((node = nodes[i++])) { Y.one(node).toggleView(config, callback); } return this; }; Y.mix(Transition.fx, { fadeOut: { opacity: 0, duration: 0.5, easing: 'ease-out' }, fadeIn: { opacity: 1, duration: 0.5, easing: 'ease-in' }, sizeOut: { height: 0, width: 0, duration: 0.75, easing: 'ease-out' }, sizeIn: { height: function(node) { return node.get('scrollHeight') + 'px'; }, width: function(node) { return node.get('scrollWidth') + 'px'; }, duration: 0.5, easing: 'ease-in', on: { start: function() { var overflow = this.getStyle('overflow'); if (overflow !== 'hidden') { // enable scrollHeight/Width this.setStyle('overflow', 'hidden'); this._transitionOverflow = overflow; } }, end: function() { if (this._transitionOverflow) { // revert overridden value this.setStyle('overflow', this._transitionOverflow); } } } } }); Y.mix(Transition.toggles, { size: ['sizeIn', 'sizeOut'], fade: ['fadeOut', 'fadeIn'] }); }, '3.3.0' ,{requires:['node-base']}); YUI.add('transition-timer', function(Y) { /* * The Transition Utility provides an API for creating advanced transitions. * @module transition */ /* * Provides the base Transition class, for animating numeric properties. * * @module transition * @submodule transition-timer */ var Transition = Y.Transition; Y.mix(Transition.prototype, { _start: function() { if (Transition.useNative) { this._runNative(); } else { this._runTimer(); } }, _runTimer: function() { var anim = this; anim._initAttrs(); Transition._running[Y.stamp(anim)] = anim; anim._startTime = new Date(); Transition._startTimer(); }, _endTimer: function() { var anim = this; delete Transition._running[Y.stamp(anim)]; anim._startTime = null; }, _runFrame: function() { var t = new Date() - this._startTime; this._runAttrs(t); }, _runAttrs: function(time) { var anim = this, node = anim._node, config = anim._config, uid = Y.stamp(node), attrs = Transition._nodeAttrs[uid], customAttr = Transition.behaviors, done = false, allDone = false, data, name, attribute, setter, elapsed, delay, d, t, i; for (name in attrs) { attribute = attrs[name]; if ((attribute && attribute.transition === anim)) { d = attribute.duration; delay = attribute.delay; elapsed = (time - delay) / 1000; t = time; data = { type: 'propertyEnd', propertyName: name, config: config, elapsedTime: elapsed }; setter = (i in customAttr && 'set' in customAttr[i]) ? customAttr[i].set : Transition.DEFAULT_SETTER; done = (t >= d); if (t > d) { t = d; } if (!delay || time >= delay) { setter(anim, name, attribute.from, attribute.to, t - delay, d - delay, attribute.easing, attribute.unit); if (done) { delete attrs[name]; anim._count--; if (config[name] && config[name].on && config[name].on.end) { config[name].on.end.call(Y.one(node), data); } //node.fire('transition:propertyEnd', data); if (!allDone && anim._count <= 0) { allDone = true; anim._end(elapsed); anim._endTimer(); } } } } } }, _initAttrs: function() { var anim = this, customAttr = Transition.behaviors, uid = Y.stamp(anim._node), attrs = Transition._nodeAttrs[uid], attribute, duration, delay, easing, val, name, mTo, mFrom, unit, begin, end; for (name in attrs) { attribute = attrs[name]; if (attrs.hasOwnProperty(name) && (attribute && attribute.transition === anim)) { duration = attribute.duration * 1000; delay = attribute.delay * 1000; easing = attribute.easing; val = attribute.value; // only allow supported properties if (name in anim._node.style || name in Y.DOM.CUSTOM_STYLES) { begin = (name in customAttr && 'get' in customAttr[name]) ? customAttr[name].get(anim, name) : Transition.DEFAULT_GETTER(anim, name); mFrom = Transition.RE_UNITS.exec(begin); mTo = Transition.RE_UNITS.exec(val); begin = mFrom ? mFrom[1] : begin; end = mTo ? mTo[1] : val; unit = mTo ? mTo[2] : mFrom ? mFrom[2] : ''; // one might be zero TODO: mixed units if (!unit && Transition.RE_DEFAULT_UNIT.test(name)) { unit = Transition.DEFAULT_UNIT; } if (typeof easing === 'string') { if (easing.indexOf('cubic-bezier') > -1) { easing = easing.substring(13, easing.length - 1).split(','); } else if (Transition.easings[easing]) { easing = Transition.easings[easing]; } } attribute.from = Number(begin); attribute.to = Number(end); attribute.unit = unit; attribute.easing = easing; attribute.duration = duration + delay; attribute.delay = delay; } else { delete attrs[name]; anim._count--; } } } }, destroy: function() { this.detachAll(); this._node = null; } }, true); Y.mix(Y.Transition, { _runtimeAttrs: {}, /* * Regex of properties that should use the default unit. * * @property RE_DEFAULT_UNIT * @static */ RE_DEFAULT_UNIT: /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i, /* * The default unit to use with properties that pass the RE_DEFAULT_UNIT test. * * @property DEFAULT_UNIT * @static */ DEFAULT_UNIT: 'px', /* * Time in milliseconds passed to setInterval for frame processing * * @property intervalTime * @default 20 * @static */ intervalTime: 20, /* * Bucket for custom getters and setters * * @property behaviors * @static */ behaviors: { left: { get: function(anim, attr) { return Y.DOM._getAttrOffset(anim._node, attr); } } }, /* * The default setter to use when setting object properties. * * @property DEFAULT_SETTER * @static */ DEFAULT_SETTER: function(anim, att, from, to, elapsed, duration, fn, unit) { from = Number(from); to = Number(to); var node = anim._node, val = Transition.cubicBezier(fn, elapsed / duration); val = from + val[0] * (to - from); if (node) { if (att in node.style || att in Y.DOM.CUSTOM_STYLES) { unit = unit || ''; Y.DOM.setStyle(node, att, val + unit); } } else { anim._end(); } }, /* * The default getter to use when getting object properties. * * @property DEFAULT_GETTER * @static */ DEFAULT_GETTER: function(anim, att) { var node = anim._node, val = ''; if (att in node.style || att in Y.DOM.CUSTOM_STYLES) { val = Y.DOM.getComputedStyle(node, att); } return val; }, _startTimer: function() { if (!Transition._timer) { Transition._timer = setInterval(Transition._runFrame, Transition.intervalTime); } }, _stopTimer: function() { clearInterval(Transition._timer); Transition._timer = null; }, /* * Called per Interval to handle each animation frame. * @method _runFrame * @private * @static */ _runFrame: function() { var done = true, anim; for (anim in Transition._running) { if (Transition._running[anim]._runFrame) { done = false; Transition._running[anim]._runFrame(); } } if (done) { Transition._stopTimer(); } }, cubicBezier: function(p, t) { var x0 = 0, y0 = 0, x1 = p[0], y1 = p[1], x2 = p[2], y2 = p[3], x3 = 1, y3 = 0, A = x3 - 3 * x2 + 3 * x1 - x0, B = 3 * x2 - 6 * x1 + 3 * x0, C = 3 * x1 - 3 * x0, D = x0, E = y3 - 3 * y2 + 3 * y1 - y0, F = 3 * y2 - 6 * y1 + 3 * y0, G = 3 * y1 - 3 * y0, H = y0, x = (((A*t) + B)*t + C)*t + D, y = (((E*t) + F)*t + G)*t + H; return [x, y]; }, easings: { ease: [0.25, 0, 1, 0.25], linear: [0, 0, 1, 1], 'ease-in': [0.42, 0, 1, 1], 'ease-out': [0, 0, 0.58, 1], 'ease-in-out': [0.42, 0, 0.58, 1] }, _running: {}, _timer: null, RE_UNITS: /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/ }, true); Transition.behaviors.top = Transition.behaviors.bottom = Transition.behaviors.right = Transition.behaviors.left; Y.Transition = Transition; }, '3.3.0' ,{requires:['transition-native', 'node-style']}); YUI.add('transition', function(Y){}, '3.3.0' ,{use:['transition-native', 'transition-timer']}); YUI.add('selector-css3', function(Y) { /** * The selector css3 module provides support for css3 selectors. * @module dom * @submodule selector-css3 * @for Selector */ /* an+b = get every _a_th node starting at the _b_th 0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n") an+0 = get every _a_th element, "0" may be omitted */ Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/; Y.Selector._getNth = function(node, expr, tag, reverse) { Y.Selector._reNth.test(expr); var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_) n = RegExp.$2, // "n" oddeven = RegExp.$3, // "odd" or "even" b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_ result = [], siblings = Y.Selector._children(node.parentNode, tag), op; if (oddeven) { a = 2; // always every other op = '+'; n = 'n'; b = (oddeven === 'odd') ? 1 : 0; } else if ( isNaN(a) ) { a = (n) ? 1 : 0; // start from the first or no repeat } if (a === 0) { // just the first if (reverse) { b = siblings.length - b + 1; } if (siblings[b - 1] === node) { return true; } else { return false; } } else if (a < 0) { reverse = !!reverse; a = Math.abs(a); } if (!reverse) { for (var i = b - 1, len = siblings.length; i < len; i += a) { if ( i >= 0 && siblings[i] === node ) { return true; } } } else { for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) { if ( i < len && siblings[i] === node ) { return true; } } } return false; }; Y.mix(Y.Selector.pseudos, { 'root': function(node) { return node === node.ownerDocument.documentElement; }, 'nth-child': function(node, expr) { return Y.Selector._getNth(node, expr); }, 'nth-last-child': function(node, expr) { return Y.Selector._getNth(node, expr, null, true); }, 'nth-of-type': function(node, expr) { return Y.Selector._getNth(node, expr, node.tagName); }, 'nth-last-of-type': function(node, expr) { return Y.Selector._getNth(node, expr, node.tagName, true); }, 'last-child': function(node) { var children = Y.Selector._children(node.parentNode); return children[children.length - 1] === node; }, 'first-of-type': function(node) { return Y.Selector._children(node.parentNode, node.tagName)[0] === node; }, 'last-of-type': function(node) { var children = Y.Selector._children(node.parentNode, node.tagName); return children[children.length - 1] === node; }, 'only-child': function(node) { var children = Y.Selector._children(node.parentNode); return children.length === 1 && children[0] === node; }, 'only-of-type': function(node) { var children = Y.Selector._children(node.parentNode, node.tagName); return children.length === 1 && children[0] === node; }, 'empty': function(node) { return node.childNodes.length === 0; }, 'not': function(node, expr) { return !Y.Selector.test(node, expr); }, 'contains': function(node, expr) { var text = node.innerText || node.textContent || ''; return text.indexOf(expr) > -1; }, 'checked': function(node) { return (node.checked === true || node.selected === true); }, enabled: function(node) { return (node.disabled !== undefined && !node.disabled); }, disabled: function(node) { return (node.disabled); } }); Y.mix(Y.Selector.operators, { '^=': '^{val}', // Match starts with value '$=': '{val}$', // Match ends with value '*=': '{val}' // Match contains value as substring }); Y.Selector.combinators['~'] = { axis: 'previousSibling' }; }, '3.3.0' ,{requires:['dom-base', 'selector-native', 'selector-css2']}); YUI.add('dom-style-ie', function(Y) { (function(Y) { var HAS_LAYOUT = 'hasLayout', PX = 'px', FILTER = 'filter', FILTERS = 'filters', OPACITY = 'opacity', AUTO = 'auto', BORDER_WIDTH = 'borderWidth', BORDER_TOP_WIDTH = 'borderTopWidth', BORDER_RIGHT_WIDTH = 'borderRightWidth', BORDER_BOTTOM_WIDTH = 'borderBottomWidth', BORDER_LEFT_WIDTH = 'borderLeftWidth', WIDTH = 'width', HEIGHT = 'height', TRANSPARENT = 'transparent', VISIBLE = 'visible', GET_COMPUTED_STYLE = 'getComputedStyle', UNDEFINED = undefined, documentElement = Y.config.doc.documentElement, testFeature = Y.Features.test, addFeature = Y.Features.add, // TODO: unit-less lineHeight (e.g. 1.22) re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i, isIE8 = (Y.UA.ie >= 8), _getStyleObj = function(node) { return node.currentStyle || node.style; }, ComputedStyle = { CUSTOM_STYLES: {}, get: function(el, property) { var value = '', current; if (el) { current = _getStyleObj(el)[property]; if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) { value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el); } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert value = current; } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function value = Y.DOM.IE.COMPUTED[property](el, property); } else if (re_unit.test(current)) { // convert to pixel value = ComputedStyle.getPixel(el, property) + PX; } else { value = current; } } return value; }, sizeOffsets: { width: ['Left', 'Right'], height: ['Top', 'Bottom'], top: ['Top'], bottom: ['Bottom'] }, getOffset: function(el, prop) { var current = _getStyleObj(el)[prop], // value of "width", "top", etc. capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc. offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc. pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc. sizeOffsets = ComputedStyle.sizeOffsets[prop], mode = el.ownerDocument.compatMode, value = ''; // IE pixelWidth incorrect for percent // manually compute by subtracting padding and border from offset size // NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used // reverting to auto from auto causes position stacking issues (old impl) if (current === AUTO || current.indexOf('%') > -1) { value = el['offset' + capped]; if (mode !== 'BackCompat') { if (sizeOffsets[0]) { value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]); value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1); } if (sizeOffsets[1]) { value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]); value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1); } } } else { // use style.pixelWidth, etc. to convert to pixels // need to map style.width to currentStyle (no currentStyle.pixelWidth) if (!el.style[pixel] && !el.style[prop]) { el.style[prop] = current; } value = el.style[pixel]; } return value + PX; }, borderMap: { thin: (isIE8) ? '1px' : '2px', medium: (isIE8) ? '3px': '4px', thick: (isIE8) ? '5px' : '6px' }, getBorderWidth: function(el, property, omitUnit) { var unit = omitUnit ? '' : PX, current = el.currentStyle[property]; if (current.indexOf(PX) < 0) { // look up keywords if a border exists if (ComputedStyle.borderMap[current] && el.currentStyle.borderStyle !== 'none') { current = ComputedStyle.borderMap[current]; } else { // otherwise no border (default is "medium") current = 0; } } return (omitUnit) ? parseFloat(current) : current; }, getPixel: function(node, att) { // use pixelRight to convert to px var val = null, style = _getStyleObj(node), styleRight = style.right, current = style[att]; node.style.right = current; val = node.style.pixelRight; node.style.right = styleRight; // revert return val; }, getMargin: function(node, att) { var val, style = _getStyleObj(node); if (style[att] == AUTO) { val = 0; } else { val = ComputedStyle.getPixel(node, att); } return val + PX; }, getVisibility: function(node, att) { var current; while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test node = node.parentNode; } return (current) ? current[att] : VISIBLE; }, getColor: function(node, att) { var current = _getStyleObj(node)[att]; if (!current || current === TRANSPARENT) { Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) { current = _getStyleObj(parent)[att]; if (current && current !== TRANSPARENT) { node = parent; return true; } }); } return Y.Color.toRGB(current); }, getBorderColor: function(node, att) { var current = _getStyleObj(node), val = current[att] || current.color; return Y.Color.toRGB(Y.Color.toHex(val)); } }, //fontSize: getPixelFont, IEComputed = {}; addFeature('style', 'computedStyle', { test: function() { return 'getComputedStyle' in Y.config.win; } }); addFeature('style', 'opacity', { test: function() { return 'opacity' in documentElement.style; } }); addFeature('style', 'filter', { test: function() { return 'filters' in documentElement; } }); // use alpha filter for IE opacity if (!testFeature('style', 'opacity') && testFeature('style', 'filter')) { Y.DOM.CUSTOM_STYLES[OPACITY] = { get: function(node) { var val = 100; try { // will error if no DXImageTransform val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY]; } catch(e) { try { // make sure its in the document val = node[FILTERS]('alpha')[OPACITY]; } catch(err) { } } return val / 100; }, set: function(node, val, style) { var current, styleObj = _getStyleObj(node), currentFilter = styleObj[FILTER]; style = style || node.style; if (val === '') { // normalize inline style behavior current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity val = current; } if (typeof currentFilter == 'string') { // in case not appended style[FILTER] = currentFilter.replace(/alpha([^)]*\))/gi, '') + ((val < 1) ? 'alpha(' + OPACITY + '=' + val * 100 + ')' : ''); if (!style[FILTER]) { style.removeAttribute(FILTER); } if (!styleObj[HAS_LAYOUT]) { style.zoom = 1; // needs layout } } } }; } try { Y.config.doc.createElement('div').style.height = '-1px'; } catch(e) { // IE throws error on invalid style set; trap common cases Y.DOM.CUSTOM_STYLES.height = { set: function(node, val, style) { var floatVal = parseFloat(val); if (floatVal >= 0 || val === 'auto' || val === '') { style.height = val; } else { } } }; Y.DOM.CUSTOM_STYLES.width = { set: function(node, val, style) { var floatVal = parseFloat(val); if (floatVal >= 0 || val === 'auto' || val === '') { style.width = val; } else { } } }; } if (!testFeature('style', 'computedStyle')) { // TODO: top, right, bottom, left IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset; IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor; IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] = IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] = ComputedStyle.getBorderWidth; IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom = IEComputed.marginLeft = ComputedStyle.getMargin; IEComputed.visibility = ComputedStyle.getVisibility; IEComputed.borderColor = IEComputed.borderTopColor = IEComputed.borderRightColor = IEComputed.borderBottomColor = IEComputed.borderLeftColor = ComputedStyle.getBorderColor; Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get; Y.namespace('DOM.IE'); Y.DOM.IE.COMPUTED = IEComputed; Y.DOM.IE.ComputedStyle = ComputedStyle; } })(Y); }, '3.3.0' ,{requires:['dom-style']}); YUI.add('simpleyui', function(Y) { // empty }, '3.3.0' ,{use:['yui','oop','dom','event-custom-base','event-base','pluginhost','node','event-delegate','io-base','json-parse','transition','selector-css3','dom-style-ie','querystring-stringify-simple']}); var Y = YUI().use('*');