3
Copyright 2011 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
8
* The YUI module contains the components required for building the YUI seed
9
* file. This includes the script loading mechanism, a simple queue, and
10
* the core utilities for the library.
15
if (typeof YUI != 'undefined') {
20
* The YUI global namespace object. If YUI is already defined, the
21
* existing YUI object will not be overwritten so that defined
22
* namespaces are preserved. It is the constructor for the object
23
* the end user interacts with. As indicated below, each instance
24
* has full custom event support, but only if the event system
25
* is available. This is a self-instantiable factory function. You
26
* can invoke it directly like this:
28
* YUI().use('*', function(Y) {
32
* But it also works like this:
40
* @param o* {object} 0..n optional configuration objects. these values
41
* are store in Y.config. See <a href="config.html">Config</a> for the list of supported
46
var YUI = function() {
51
instanceOf = function(o, type) {
52
return (o && o.hasOwnProperty && (o instanceof type));
54
gconf = (typeof YUI_config !== 'undefined') && YUI_config;
56
if (!(instanceOf(Y, YUI))) {
59
// set up the core environment
62
// YUI.GlobalConfig is a master configuration that might span
63
// multiple contexts in a non-browser environment. It is applied
64
// first to all instances in all contexts.
65
if (YUI.GlobalConfig) {
66
Y.applyConfig(YUI.GlobalConfig);
69
// YUI_Config is a page-level config. It is applied to all
70
// instances created on the page. This is applied after
71
// YUI.GlobalConfig, and before the instance level configuration
77
// bind the specified additional modules for this instance
84
// Each instance can accept one or more configuration objects.
85
// These are applied after YUI.GlobalConfig and YUI_Config,
86
// overriding values set in those config files if there is a '
89
Y.applyConfig(args[i]);
95
Y.instanceOf = instanceOf;
105
BASE = 'http://yui.yahooapis.com/',
106
DOC_LABEL = 'yui3-js-enabled',
107
NOOP = function() {},
108
SLICE = Array.prototype.slice,
109
APPLY_TO_AUTH = { 'io.xdrReady': 1, // the functions applyTo
110
'io.xdrResponse': 1, // can call. this should
111
'SWF.eventHandler': 1 }, // be done at build time
112
hasWin = (typeof window != 'undefined'),
113
win = (hasWin) ? window : null,
114
doc = (hasWin) ? win.document : null,
115
docEl = doc && doc.documentElement,
116
docClass = docEl && docEl.className,
118
time = new Date().getTime(),
119
add = function(el, type, fn, capture) {
120
if (el && el.addEventListener) {
121
el.addEventListener(type, fn, capture);
122
} else if (el && el.attachEvent) {
123
el.attachEvent('on' + type, fn);
126
remove = function(el, type, fn, capture) {
127
if (el && el.removeEventListener) {
128
// this can throw an uncaught exception in FF
130
el.removeEventListener(type, fn, capture);
132
} else if (el && el.detachEvent) {
133
el.detachEvent('on' + type, fn);
136
handleLoad = function() {
137
YUI.Env.windowLoaded = true;
138
YUI.Env.DOMReady = true;
140
remove(window, 'load', handleLoad);
143
getLoader = function(Y, o) {
144
var loader = Y.Env._loader;
146
//loader._config(Y.config);
147
loader.ignoreRegistered = false;
150
loader.required = [];
151
loader.loadType = null;
153
loader = new Y.Loader(Y.config);
154
Y.Env._loader = loader;
160
clobber = function(r, s) {
162
if (s.hasOwnProperty(i)) {
168
ALREADY_DONE = { success: true };
170
// Stamp the documentElement (HTML) with a class of "yui-loaded" to
171
// enable styles that need to key off of JS being enabled.
172
if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
176
docClass += DOC_LABEL;
177
docEl.className = docClass;
180
if (VERSION.indexOf('@') > -1) {
181
VERSION = '3.3.0'; // dev time hack for cdn test
186
* Applies a new configuration object to the YUI instance config.
187
* This will merge new group/module definitions, and will also
188
* update the loader cache if necessary. Updating Y.config directly
189
* will not update the cache.
190
* @method applyConfig
191
* @param {object} the configuration object.
194
applyConfig: function(o) {
201
config = this.config,
202
mods = config.modules,
203
groups = config.groups,
205
loader = this.Env._loader;
208
if (o.hasOwnProperty(name)) {
210
if (mods && name == 'modules') {
212
} else if (groups && name == 'groups') {
213
clobber(groups, attr);
214
} else if (rls && name == 'rls') {
216
} else if (name == 'win') {
217
config[name] = attr.contentWindow || attr;
218
config.doc = config[name].document;
219
} else if (name == '_yuid') {
232
* Old way to apply a config to the instance (calls `applyConfig` under the hood)
235
* @param {Object} o The config to apply
237
_config: function(o) {
242
* Initialize this YUI instance
254
* The version number of the YUI instance.
262
mods: {}, // flat module map
263
versions: {}, // version module map
265
cdn: BASE + VERSION + '/build/',
266
// bootstrapped: false,
277
// I'll start at the \b(simpleyui).
278
// 1. Look in the test string for "simpleyui" or "yui" or
279
// "yui-base" or "yui-rls" or "yui-foobar" that comes after a word break. That is, it
280
// can't match "foyui" or "i_heart_simpleyui". This can be anywhere in the string.
281
// 2. After #1 must come a forward slash followed by the string matched in #1, so
282
// "yui-base/yui-base" or "simpleyui/simpleyui" or "yui-pants/yui-pants".
283
// 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min",
284
// so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt".
285
// 4. This is followed by ".js", so "yui/yui.js", "simpleyui/simpleyui-min.js"
286
// 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string,
287
// then capture the junk between the LAST "&" and the string in 1-4. So
288
// "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-rls/yui-rls.js"
289
// will capture "3.3.0/build/"
293
// (?:[^&]*&) followed by 0..n characters followed by an &
294
// * in fact, find as many sets of characters followed by a & as you can
295
// ([^&]*) capture the stuff after the last & in \1
296
// )? but it's ok if all this ?junk&more_junk stuff isn't even there
297
// \b(simpleyui| after a word break find either the string "simpleyui" or
298
// yui(?:-\w+)? the string "yui" optionally followed by a -, then more characters
299
// ) and store the simpleyui or yui-* string in \2
300
// \/\2 then comes a / followed by the simpleyui or yui-* string in \2
301
// (?:-(min|debug))? optionally followed by "-min" or "-debug"
302
// .js and ending in ".js"
303
_BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(simpleyui|yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/,
304
parseBasePath: function(src, pattern) {
305
var match = src.match(pattern),
309
path = RegExp.leftContext || src.slice(0, src.indexOf(match[0]));
311
// this is to set up the path to the loader. The file
312
// filter for loader should match the yui include.
315
// extract correct path for mixed combo urls
316
// http://yuilibrary.com/projects/yui3/ticket/2528423
318
path += '?' + match[1];
327
getBase: G_ENV && G_ENV.getBase ||
329
var nodes = (doc && doc.getElementsByTagName('script')) || [],
330
path = Env.cdn, parsed,
333
for (i = 0, len = nodes.length; i < len; ++i) {
336
parsed = Y.Env.parseBasePath(src, pattern);
338
filter = parsed.filter;
353
Env._loaded[VERSION] = {};
355
if (G_ENV && Y !== YUI) {
356
Env._yidx = ++G_ENV._yidx;
357
Env._guidp = ('yui_' + VERSION + '_' +
358
Env._yidx + '_' + time).replace(/\./g, '_');
359
} else if (YUI._YUI) {
361
G_ENV = YUI._YUI.Env;
362
Env._yidx += G_ENV._yidx;
363
Env._uidx += G_ENV._uidx;
365
for (prop in G_ENV) {
366
if (!(prop in Env)) {
367
Env[prop] = G_ENV[prop];
381
// configuration defaults
382
Y.config = Y.config || {
386
useBrowserConsole: true,
395
if (YUI.Env.rls_disabled) {
396
Y.config.use_rls = false;
399
Y.config.lang = Y.config.lang || 'en-US';
401
Y.config.base = YUI.config.base || Y.Env.getBase(Y.Env._BASE_RE);
403
if (!filter || (!('mindebug').indexOf(filter))) {
406
filter = (filter) ? '-' + filter : filter;
407
Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js';
412
* Finishes the instance setup. Attaches whatever modules were defined
413
* when the yui modules was registered.
417
_setup: function(o) {
421
extras = Y.config.core || ['get','features','intl-base','yui-log','yui-later'];
423
for (i = 0; i < extras.length; i++) {
424
if (mods[extras[i]]) {
425
core.push(extras[i]);
429
Y._attach(['yui-base']);
432
// Y.log(Y.id + ' initialized', 'info', 'yui');
436
* Executes a method on a YUI instance with
437
* the specified id if the specified method is whitelisted.
439
* @param id {String} the YUI instance id.
440
* @param method {String} the name of the method to exectute.
442
* @param args {Array} the arguments to apply to the method.
443
* @return {Object} the return value from the applied method or null.
445
applyTo: function(id, method, args) {
446
if (!(method in APPLY_TO_AUTH)) {
447
this.log(method + ': applyTo not allowed', 'warn', 'yui');
451
var instance = instances[id], nest, m, i;
453
nest = method.split('.');
455
for (i = 0; i < nest.length; i = i + 1) {
458
this.log('applyTo not found: ' + method, 'warn', 'yui');
461
return m.apply(instance, args);
468
* Registers a module with the YUI global. The easiest way to create a
469
* first-class YUI module is to use the YUI component build tool.
471
* http://yuilibrary.com/projects/builder
473
* The build system will produce the `YUI.add` wrapper for you module, along
474
* with any configuration info required for the module.
476
* @param name {String} module name.
477
* @param fn {Function} entry point into the module that
478
* is used to bind module to the YUI instance.
479
* @param version {String} version string.
480
* @param details {Object} optional config data:
481
* @param details.requires {Array} features that must be present before this module can be attached.
482
* @param details.optional {Array} optional features that should be present if loadOptional
483
* is defined. Note: modules are not often loaded this way in YUI 3,
484
* but this field is still useful to inform the user that certain
485
* features in the component will require additional dependencies.
486
* @param details.use {Array} features that are included within this module which need to
487
* be attached automatically when this module is attached. This
488
* supports the YUI 3 rollup system -- a module with submodules
489
* defined will need to have the submodules listed in the 'use'
490
* config. The YUI component build tool does this for you.
491
* @return {YUI} the YUI instance.
494
add: function(name, fn, version, details) {
495
details = details || {};
504
i, versions = env.versions;
506
env.mods[name] = mod;
507
versions[version] = versions[version] || {};
508
versions[version][name] = mod;
510
for (i in instances) {
511
if (instances.hasOwnProperty(i)) {
512
loader = instances[i].Env._loader;
514
if (!loader.moduleInfo[name]) {
515
loader.addModule(details, name);
525
* Executes the function associated with each required
526
* module, binding the module to the YUI instance.
530
_attach: function(r, moot) {
531
var i, name, mod, details, req, use, after,
533
aliases = YUI.Env.aliases,
535
done = Y.Env._attached,
536
len = r.length, loader;
538
//console.info('attaching: ' + r, 'info', 'yui');
540
for (i = 0; i < len; i++) {
544
if (aliases && aliases[name]) {
545
Y._attach(aliases[name]);
549
loader = Y.Env._loader;
550
if (loader && loader.moduleInfo[name]) {
551
mod = loader.moduleInfo[name];
557
// Y.log('no js def for: ' + name, 'info', 'yui');
559
//if (!loader || !loader.moduleInfo[name]) {
560
//if ((!loader || !loader.moduleInfo[name]) && !moot) {
562
if (name.indexOf('skin-') === -1) {
563
Y.Env._missed.push(name);
564
Y.message('NOT loaded: ' + name, 'warn', 'yui');
569
//Don't like this, but in case a mod was asked for once, then we fetch it
570
//We need to remove it from the missed list
571
for (j = 0; j < Y.Env._missed.length; j++) {
572
if (Y.Env._missed[j] === name) {
573
Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui');
574
Y.Env._missed.splice(j, 1);
577
details = mod.details;
578
req = details.requires;
580
after = details.after;
583
for (j = 0; j < req.length; j++) {
585
if (!Y._attach(req)) {
594
for (j = 0; j < after.length; j++) {
595
if (!done[after[j]]) {
596
if (!Y._attach(after, true)) {
608
Y.error('Attach error: ' + name, e, name);
614
for (j = 0; j < use.length; j++) {
616
if (!Y._attach(use)) {
634
* Attaches one or more modules to the YUI instance. When this
635
* is executed, the requirements are analyzed, and one of
636
* several things can happen:
638
* * All requirements are available on the page -- The modules
639
* are attached to the instance. If supplied, the use callback
640
* is executed synchronously.
642
* * Modules are missing, the Get utility is not available OR
643
* the 'bootstrap' config is false -- A warning is issued about
644
* the missing modules and all available modules are attached.
646
* * Modules are missing, the Loader is not available but the Get
647
* utility is and boostrap is not false -- The loader is bootstrapped
648
* before doing the following....
650
* * Modules are missing and the Loader is available -- The loader
651
* expands the dependency tree and fetches missing modules. When
652
* the loader is finshed the callback supplied to use is executed
656
* @param modules* {String} 1-n modules to bind (uses arguments array).
657
* @param *callback {Function} callback function executed when
658
* the instance has the required functionality. If included, it
659
* must be the last parameter.
662
* // loads and attaches dd and its dependencies
663
* YUI().use('dd', function(Y) {});
665
* // loads and attaches dd and node as well as all of their dependencies (since 3.4.0)
666
* YUI().use(['dd', 'node'], function(Y) {});
668
* // attaches all modules that are available on the page
669
* YUI().use('*', function(Y) {});
671
* // intrinsic YUI gallery support (since 3.1.0)
672
* YUI().use('gallery-yql', function(Y) {});
674
* // intrinsic YUI 2in3 support (since 3.1.0)
675
* YUI().use('yui2-datatable', function(Y) {});
677
* @return {YUI} the YUI instance.
680
var args = SLICE.call(arguments, 0),
681
callback = args[args.length - 1],
688
// The last argument supplied to use can be a load complete callback
689
if (Y.Lang.isFunction(callback)) {
694
if (Y.Lang.isArray(args[0])) {
698
if (Y.config.cacheUse) {
699
while ((name = args[i++])) {
700
if (!Env._attached[name]) {
708
Y.log('already provisioned: ' + args, 'info', 'yui');
710
Y._notify(callback, ALREADY_DONE, args);
715
if (Y.config.cacheUse) {
716
while ((name = args[i++])) {
717
if (!Env._attached[name]) {
725
Y.log('already provisioned: ' + args, 'info', 'yui');
727
Y._notify(callback, ALREADY_DONE, args);
733
Y._useQueue = Y._useQueue || new Y.Queue();
734
Y._useQueue.add([args, callback]);
736
Y._use(args, function(Y, response) {
737
Y._notify(callback, response, args);
744
* Notify handler from Loader for attachment/load errors
746
* @param callback {Function} The callback to pass to the `Y.config.loadErrorFn`
747
* @param response {Object} The response returned from Loader
748
* @param args {Array} The aruments passed from Loader
751
_notify: function(callback, response, args) {
752
if (!response.success && this.config.loadErrorFn) {
753
this.config.loadErrorFn.call(this, this, callback, response, args);
754
} else if (callback) {
756
callback(this, response);
758
this.error('use callback error', e, args);
764
* This private method is called from the `use` method queue. To ensure that only one set of loading
765
* logic is performed at a time.
768
* @param args* {String} 1-n modules to bind (uses arguments array).
769
* @param *callback {Function} callback function executed when
770
* the instance has the required functionality. If included, it
771
* must be the last parameter.
773
_use: function(args, callback) {
776
this._attach(['yui-base']);
779
var len, loader, handleBoot, handleRLS,
785
queue = G_ENV._loaderQueue,
789
boot = config.bootstrap,
793
fetchCSS = config.fetchCSS,
794
process = function(names, skip) {
800
YArray.each(names, function(name) {
802
// add this module to full list of things to attach
807
// only attach a module once
812
var m = mods[name], req, use;
816
req = m.details.requires;
819
// CSS files don't register themselves, see if it has
821
if (!G_ENV._loaded[VERSION][name]) {
824
used[name] = true; // probably css
828
// make sure requirements are attached
829
if (req && req.length) {
833
// make sure we grab the submodule dependencies too
834
if (use && use.length) {
840
handleLoader = function(fromLoader) {
841
var response = fromLoader || {
847
data = response.data;
853
origMissing = missing;
857
redo = missing.length;
859
if (missing.sort().join() ==
860
origMissing.sort().join()) {
868
Y._use(args, function() {
869
Y.log('Nested use callback: ' + data, 'info', 'yui');
870
if (Y._attach(data)) {
871
Y._notify(callback, response, data);
876
// Y.log('attaching from loader: ' + data, 'info', 'yui');
877
ret = Y._attach(data);
880
Y._notify(callback, response, args);
884
if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
885
Y._use.apply(Y, Y._useQueue.next());
890
// Y.log(Y.id + ': use called: ' + a + ' :: ' + callback, 'info', 'yui');
892
// YUI().use('*'); // bind everything available
893
if (firstArg === '*') {
894
ret = Y._attach(Y.Object.keys(mods));
901
// Y.log('before loader requirements: ' + args, 'info', 'yui');
903
// use loader to expand dependencies and sort the
904
// requirements if it is available.
905
if (boot && Y.Loader && args.length) {
906
loader = getLoader(Y);
907
loader.require(args);
908
loader.ignoreRegistered = true;
909
loader.calculate(null, (fetchCSS) ? null : 'js');
910
args = loader.sorted;
913
// process each requirement and any additional requirements
914
// the module metadata specifies
917
len = missing.length;
920
missing = Y.Object.keys(YArray.hash(missing));
921
len = missing.length;
922
Y.log('Modules missing: ' + missing + ', ' + missing.length, 'info', 'yui');
926
if (boot && len && Y.Loader) {
927
// Y.log('Using loader to fetch missing deps: ' + missing, 'info', 'yui');
928
Y.log('Using Loader', 'info', 'yui');
930
loader = getLoader(Y);
931
loader.onEnd = handleLoader;
934
loader.ignoreRegistered = false;
935
loader.require(args);
936
loader.insert(null, (fetchCSS) ? null : 'js');
937
// loader.partial(missing, (fetchCSS) ? null : 'js');
939
} else if (len && Y.config.use_rls && !YUI.Env.rls_enabled) {
941
G_ENV._rls_queue = G_ENV._rls_queue || new Y.Queue();
943
// server side loader service
944
handleRLS = function(instance, argz) {
946
var rls_end = function(o) {
948
instance.rls_advance();
950
rls_url = instance._rls(argz);
953
Y.log('Fetching RLS url', 'info', 'rls');
954
instance.rls_oncomplete(function(o) {
957
instance.Get.script(rls_url, {
959
timeout: instance.config.rls_timeout,
960
onFailure: instance.rls_handleFailure,
961
onTimeout: instance.rls_handleTimeout
970
G_ENV._rls_queue.add(function() {
971
Y.log('executing queued rls request', 'info', 'rls');
972
G_ENV._rls_in_progress = true;
973
Y.rls_callback = callback;
974
Y.rls_locals(Y, args, handleRLS);
977
if (!G_ENV._rls_in_progress && G_ENV._rls_queue.size()) {
978
G_ENV._rls_queue.next()();
981
} else if (boot && len && Y.Get && !Env.bootstrapped) {
985
handleBoot = function() {
987
queue.running = false;
988
Env.bootstrapped = true;
989
G_ENV._bootstrapping = false;
990
if (Y._attach(['loader'])) {
991
Y._use(args, callback);
995
if (G_ENV._bootstrapping) {
996
Y.log('Waiting for loader', 'info', 'yui');
997
queue.add(handleBoot);
999
G_ENV._bootstrapping = true;
1000
Y.log('Fetching loader: ' + config.base + config.loaderPath, 'info', 'yui');
1001
Y.Get.script(config.base + config.loaderPath, {
1007
Y.log('Attaching available dependencies: ' + args, 'info', 'yui');
1008
ret = Y._attach(args);
1019
* Returns the namespace specified and creates it if it doesn't exist
1021
* YUI.namespace("property.package");
1022
* YUI.namespace("YAHOO.property.package");
1024
* Either of the above would create `YUI.property`, then
1025
* `YUI.property.package` (`YAHOO` is scrubbed out, this is
1026
* to remain compatible with YUI2)
1028
* Be careful when naming packages. Reserved words may work in some browsers
1029
* and not others. For instance, the following will fail in Safari:
1031
* YUI.namespace("really.long.nested.namespace");
1033
* This fails because "long" is a future reserved word in ECMAScript
1036
* @param {string*} arguments 1-n namespaces to create.
1037
* @return {object} A reference to the last namespace object created.
1039
namespace: function() {
1040
var a = arguments, o = this, i = 0, j, d, arg;
1041
for (; i < a.length; i++) {
1042
// d = ('' + a[i]).split('.');
1044
if (arg.indexOf(PERIOD)) {
1045
d = arg.split(PERIOD);
1046
for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
1047
o[d[j]] = o[d[j]] || {};
1051
o[arg] = o[arg] || {};
1057
// this is replaced if the log module is included
1060
// this is replaced if the dump module is included
1061
dump: function (o) { return ''+o; },
1064
* Report an error. The reporting mechanism is controled by
1065
* the `throwFail` configuration attribute. If throwFail is
1066
* not specified, the message is written to the Logger, otherwise
1067
* a JS error is thrown
1069
* @param msg {String} the error message.
1070
* @param e {Error|String} Optional JS error that was caught, or an error string.
1071
* @param data Optional additional info
1072
* and `throwFail` is specified, this error will be re-thrown.
1073
* @return {YUI} this YUI instance.
1075
error: function(msg, e, data) {
1079
if (Y.config.errorFn) {
1080
ret = Y.config.errorFn.apply(Y, arguments);
1083
if (Y.config.throwFail && !ret) {
1084
throw (e || new Error(msg));
1086
Y.message(msg, 'error'); // don't scrub this one
1093
* Generate an id that is unique among all YUI instances
1095
* @param pre {String} optional guid prefix.
1096
* @return {String} the guid.
1098
guid: function(pre) {
1099
var id = this.Env._guidp + '_' + (++this.Env._uidx);
1100
return (pre) ? (pre + id) : id;
1104
* Returns a `guid` associated with an object. If the object
1105
* does not have one, a new one is created unless `readOnly`
1108
* @param o {Object} The object to stamp.
1109
* @param readOnly {Boolean} if `true`, a valid guid will only
1110
* be returned if the object has one assigned to it.
1111
* @return {String} The object's guid or null.
1113
stamp: function(o, readOnly) {
1119
// IE generates its own unique ID for dom nodes
1120
// The uniqueID property of a document node returns a new ID
1121
if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
1124
uid = (typeof o === 'string') ? o : o._yuid;
1141
* Destroys the YUI instance
1145
destroy: function() {
1150
delete instances[Y.id];
1156
* instanceof check for objects that works around
1157
* memory leak in IE when the item tested is
1159
* @method instanceOf
1166
YUI.prototype = proto;
1168
// inheritance utilities are not available yet
1169
for (prop in proto) {
1170
if (proto.hasOwnProperty(prop)) {
1171
YUI[prop] = proto[prop];
1175
// set up the environment
1179
// add a window load event at load time so we can capture
1180
// the case where it fires before dynamic loading is
1182
add(window, 'load', handleLoad);
1188
YUI.Env.remove = remove;
1191
// Support the CommonJS method for exporting our single global
1192
if (typeof exports == 'object') {
1200
* The config object contains all of the configuration options for
1201
* the `YUI` instance. This object is supplied by the implementer
1202
* when instantiating a `YUI` instance. Some properties have default
1203
* values if they are not supplied by the implementer. This should
1204
* not be updated directly because some values are cached. Use
1205
* `applyConfig()` to update the config object on a YUI instance that
1206
* has already been configured.
1213
* Allows the YUI seed file to fetch the loader component and library
1214
* metadata to dynamically load additional dependencies.
1216
* @property bootstrap
1222
* Log to the browser console if debug is on and the browser has a
1223
* supported console.
1225
* @property useBrowserConsole
1231
* A hash of log sources that should be logged. If specified, only
1232
* log messages from these sources will be logged.
1234
* @property logInclude
1239
* A hash of log sources that should be not be logged. If specified,
1240
* all sources are logged if not on this list.
1242
* @property logExclude
1247
* Set to true if the yui seed file was dynamically loaded in
1248
* order to bootstrap components relying on the window load event
1249
* and the `domready` custom event.
1251
* @property injected
1257
* If `throwFail` is set, `Y.error` will generate or re-throw a JS Error.
1258
* Otherwise the failure is logged.
1260
* @property throwFail
1266
* The window/frame that this instance should operate in.
1270
* @default the window hosting YUI
1274
* The document associated with the 'win' configuration.
1278
* @default the document hosting YUI
1282
* A list of modules that defines the YUI core (overrides the default).
1289
* A list of languages in order of preference. This list is matched against
1290
* the list of available languages in modules that the YUI instance uses to
1291
* determine the best possible localization of language sensitive modules.
1292
* Languages are represented using BCP 47 language tags, such as "en-GB" for
1293
* English as used in the United Kingdom, or "zh-Hans-CN" for simplified
1294
* Chinese as used in China. The list can be provided as a comma-separated
1295
* list or as an array.
1298
* @type string|string[]
1302
* The default date format
1303
* @property dateFormat
1305
* @deprecated use configuration in `DataType.Date.format()` instead.
1309
* The default locale
1312
* @deprecated use `config.lang` instead.
1316
* The default interval when polling in milliseconds.
1317
* @property pollInterval
1323
* The number of dynamic nodes to insert by default before
1324
* automatically removing them. This applies to script nodes
1325
* because removing the node will not make the evaluated script
1326
* unavailable. Dynamic CSS is not auto purged, because removing
1327
* a linked style sheet will also remove the style definitions.
1328
* @property purgethreshold
1334
* The default interval when polling in milliseconds.
1335
* @property windowResizeDelay
1341
* Base directory for dynamic loading
1347
* The secure base dir (not implemented)
1348
* For dynamic loading.
1349
* @property secureBase
1354
* The YUI combo service base dir. Ex: `http://yui.yahooapis.com/combo?`
1355
* For dynamic loading.
1356
* @property comboBase
1361
* The root path to prepend to module path for the combo service.
1362
* Ex: 3.0.0b1/build/
1363
* For dynamic loading.
1369
* A filter to apply to result urls. This filter will modify the default
1370
* path for all modules. The default path for the YUI library is the
1371
* minified version of the files (e.g., event-min.js). The filter property
1372
* can be a predefined filter or a custom filter. The valid predefined
1376
* <dd>Selects the debug versions of the library (e.g., event-debug.js).
1377
* This option will automatically include the Logger widget</dd>
1379
* <dd>Selects the non-minified version of the library (e.g., event.js).</dd>
1381
* You can also define a custom filter, which must be an object literal
1382
* containing a search expression and a replace string:
1385
* 'searchExp': "-min\\.js",
1386
* 'replaceStr': "-debug.js"
1389
* For dynamic loading.
1392
* @type string|object
1396
* The `skin` config let's you configure application level skin
1397
* customizations. It contains the following attributes which
1398
* can be specified to override the defaults:
1400
* // The default skin, which is automatically applied if not
1401
* // overriden by a component-specific skin definition.
1402
* // Change this in to apply a different skin globally
1403
* defaultSkin: 'sam',
1405
* // This is combined with the loader base property to get
1406
* // the default root directory for a skin.
1407
* base: 'assets/skins/',
1409
* // Any component-specific overrides can be specified here,
1410
* // making it possible to load different skins for different
1411
* // components. It is possible to load more than one skin
1412
* // for a given component as well.
1414
* slider: ['capsule', 'round']
1417
* For dynamic loading.
1423
* Hash of per-component filter specification. If specified for a given
1424
* component, this overrides the filter config.
1426
* For dynamic loading.
1432
* Use the YUI combo service to reduce the number of http connections
1433
* required to load your dependencies. Turning this off will
1434
* disable combo handling for YUI and all module groups configured
1435
* with a combo service.
1437
* For dynamic loading.
1441
* @default true if 'base' is not supplied, false if it is.
1445
* A list of modules that should never be dynamically loaded
1452
* A list of modules that should always be loaded when required, even if already
1453
* present on the page.
1460
* Node or id for a node that should be used as the insertion point for new
1461
* nodes. For dynamic loading.
1463
* @property insertBefore
1468
* Object literal containing attributes to add to dynamically loaded script
1470
* @property jsAttributes
1475
* Object literal containing attributes to add to dynamically loaded link
1477
* @property cssAttributes
1482
* Number of milliseconds before a timeout occurs when dynamically
1483
* loading nodes. If not set, there is no timeout.
1489
* Callback for the 'CSSComplete' event. When dynamically loading YUI
1490
* components with CSS, this property fires when the CSS is finished
1491
* loading but script loading is still ongoing. This provides an
1492
* opportunity to enhance the presentation of a loading page a little
1493
* bit before the entire loading process is done.
1500
* A hash of module definitions to add to the list of YUI components.
1501
* These components can then be dynamically loaded side by side with
1502
* YUI via the `use()` method. This is a hash, the key is the module
1503
* name, and the value is an object literal specifying the metdata
1504
* for the module. See `Loader.addModule` for the supported module
1505
* metadata fields. Also see groups, which provides a way to
1506
* configure the base and combo spec for a set of modules.
1510
* requires: ['node'],
1511
* fullpath: 'http://myserver.mydomain.com/mymod1/mymod1.js'
1514
* requires: ['mymod1'],
1515
* fullpath: 'http://myserver.mydomain.com/mymod2/mymod2.js'
1524
* A hash of module group definitions. It for each group you
1525
* can specify a list of modules and the base path and
1526
* combo spec to use when dynamically loading the modules.
1530
* // specify whether or not this group has a combo service
1533
* // the base path for non-combo paths
1534
* base: 'http://yui.yahooapis.com/2.8.0r4/build/',
1536
* // the path to the combo service
1537
* comboBase: 'http://yui.yahooapis.com/combo?',
1539
* // a fragment to prepend to the path attribute when
1540
* // when building combo urls
1541
* root: '2.8.0r4/build/',
1543
* // the module definitions
1546
* path: "yahoo-dom-event/yahoo-dom-event.js"
1549
* path: "animation/animation.js",
1550
* requires: ['yui2_yde']
1561
* The loader 'path' attribute to the loader itself. This is combined
1562
* with the 'base' attribute to dynamically load the loader component
1563
* when boostrapping with the get utility alone.
1565
* @property loaderPath
1567
* @default loader/loader-min.js
1571
* Specifies whether or not YUI().use(...) will attempt to load CSS
1572
* resources at all. Any truthy value will cause CSS dependencies
1573
* to load when fetching script. The special value 'force' will
1574
* cause CSS dependencies to be loaded even if no script is needed.
1576
* @property fetchCSS
1577
* @type boolean|string
1582
* The default gallery version to build gallery module urls
1589
* The default YUI 2 version to build yui2 module urls. This is for
1590
* intrinsic YUI 2 support via the 2in3 project. Also see the '2in3'
1591
* config for pulling different revisions of the wrapped YUI 2
1600
* The 2in3 project is a deployment of the various versions of YUI 2
1601
* deployed as first-class YUI 3 modules. Eventually, the wrapper
1602
* for the modules will change (but the underlying YUI 2 code will
1603
* be the same), and you can select a particular version of
1604
* the wrapper modules via this config.
1612
* Alternative console log function for use in environments without
1613
* a supported native console. The function is executed in the
1614
* YUI instance context.
1621
* A callback to execute when Y.error is called. It receives the
1622
* error message and an javascript error object if Y.error was
1623
* executed because a javascript error was caught. The function
1624
* is executed in the YUI instance context.
1632
* A callback to execute when the loader fails to load one or
1633
* more resource. This could be because of a script load
1634
* failure. It can also fail if a javascript module fails
1635
* to register itself, but only when the 'requireRegistration'
1636
* is true. If this function is defined, the use() callback will
1637
* only be called when the loader succeeds, otherwise it always
1638
* executes unless there was a javascript error when attaching
1642
* @property loadErrorFn
1647
* When set to true, the YUI loader will expect that all modules
1648
* it is responsible for loading will be first-class YUI modules
1649
* that register themselves with the YUI global. If this is
1650
* set to true, loader will fail if the module registration fails
1651
* to happen after the script is loaded.
1654
* @property requireRegistration
1660
* Cache serviced use() requests.
1662
* @property cacheUse
1665
* @deprecated no longer used
1669
* The parameter defaults for the remote loader service.
1670
* Requires the rls submodule. The properties that are
1673
* * `m`: comma separated list of module requirements. This
1674
* must be the param name even for custom implemetations.
1675
* * `v`: the version of YUI to load. Defaults to the version
1676
* of YUI that is being used.
1677
* * `gv`: the version of the gallery to load (see the gallery config)
1678
* * `env`: comma separated list of modules already on the page.
1679
* this must be the param name even for custom implemetations.
1680
* * `lang`: the languages supported on the page (see the lang config)
1681
* * `'2in3v'`: the version of the 2in3 wrapper to use (see the 2in3 config).
1682
* * `'2v'`: the version of yui2 to use in the yui 2in3 wrappers
1683
* * `filt`: a filter def to apply to the urls (see the filter config).
1684
* * `filts`: a list of custom filters to apply per module
1685
* * `tests`: this is a map of conditional module test function id keys
1686
* with the values of 1 if the test passes, 0 if not. This must be
1687
* the name of the querystring param in custom templates.
1694
* The base path to the remote loader service
1697
* @property rls_base
1701
* The template to use for building the querystring portion
1702
* of the remote loader service url. The default is determined
1703
* by the rls config -- each property that has a value will be
1707
* @property rls_tmpl
1709
* m={m}&v={v}&env={env}&lang={lang}&filt={filt}&tests={tests}
1714
* Configure the instance to use a remote loader service instead of
1715
* the client loader.
1720
YUI.add('yui-base', function(Y) {
1725
* @submodule yui-base
1728
* The YUI module contains the components required for building the YUI
1729
* seed file. This includes the script loading mechanism, a simple queue,
1730
* and the core utilities for the library.
1732
* @submodule yui-base
1736
* Provides core language utilites and extensions used throughout YUI.
1742
var L = Y.Lang || (Y.Lang = {}),
1744
STRING_PROTO = String.prototype,
1745
TOSTRING = Object.prototype.toString,
1748
'undefined' : 'undefined',
1749
'number' : 'number',
1750
'boolean' : 'boolean',
1751
'string' : 'string',
1752
'[object Function]': 'function',
1753
'[object RegExp]' : 'regexp',
1754
'[object Array]' : 'array',
1755
'[object Date]' : 'date',
1756
'[object Error]' : 'error'
1759
SUBREGEX = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
1760
TRIMREGEX = /^\s+|\s+$/g,
1762
// If either MooTools or Prototype is on the page, then there's a chance that we
1763
// can't trust "native" language features to actually be native. When this is
1764
// the case, we take the safe route and fall back to our own non-native
1767
unsafeNatives = win && !!(win.MooTools || win.Prototype);
1770
* Determines whether or not the provided item is an array.
1772
* Returns `false` for array-like collections such as the function `arguments`
1773
* collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to
1774
* test for an array-like collection.
1777
* @param o The object to test.
1778
* @return {boolean} true if o is an array.
1781
L.isArray = (!unsafeNatives && Array.isArray) || function (o) {
1782
return L.type(o) === 'array';
1786
* Determines whether or not the provided item is a boolean.
1789
* @param o The object to test.
1790
* @return {boolean} true if o is a boolean.
1792
L.isBoolean = function(o) {
1793
return typeof o === 'boolean';
1798
* Determines whether or not the provided item is a function.
1799
* Note: Internet Explorer thinks certain functions are objects:
1803
* var obj = document.createElement("object");
1804
* Y.Lang.isFunction(obj.getAttribute) // reports false in IE
1806
* var input = document.createElement("input"); // append to body
1807
* Y.Lang.isFunction(input.focus) // reports false in IE
1811
* You will have to implement additional tests if these functions
1815
* @method isFunction
1817
* @param o The object to test.
1818
* @return {boolean} true if o is a function.
1820
L.isFunction = function(o) {
1821
return L.type(o) === 'function';
1825
* Determines whether or not the supplied item is a date instance.
1828
* @param o The object to test.
1829
* @return {boolean} true if o is a date.
1831
L.isDate = function(o) {
1832
return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o);
1836
* Determines whether or not the provided item is null.
1839
* @param o The object to test.
1840
* @return {boolean} true if o is null.
1842
L.isNull = function(o) {
1847
* Determines whether or not the provided item is a legal number.
1850
* @param o The object to test.
1851
* @return {boolean} true if o is a number.
1853
L.isNumber = function(o) {
1854
return typeof o === 'number' && isFinite(o);
1858
* Determines whether or not the provided item is of type object
1859
* or function. Note that arrays are also objects, so
1860
* <code>Y.Lang.isObject([]) === true</code>.
1863
* @param o The object to test.
1864
* @param failfn {boolean} fail if the input is a function.
1865
* @return {boolean} true if o is an object.
1866
* @see isPlainObject
1868
L.isObject = function(o, failfn) {
1870
return (o && (t === 'object' ||
1871
(!failfn && (t === 'function' || L.isFunction(o))))) || false;
1875
* Determines whether or not the provided item is a string.
1878
* @param o The object to test.
1879
* @return {boolean} true if o is a string.
1881
L.isString = function(o) {
1882
return typeof o === 'string';
1886
* Determines whether or not the provided item is undefined.
1887
* @method isUndefined
1889
* @param o The object to test.
1890
* @return {boolean} true if o is undefined.
1892
L.isUndefined = function(o) {
1893
return typeof o === 'undefined';
1897
* Returns a string without any leading or trailing whitespace. If
1898
* the input is not a string, the input will be returned untouched.
1901
* @param s {string} the string to trim.
1902
* @return {string} the trimmed string.
1904
L.trim = STRING_PROTO.trim ? function(s) {
1905
return s && s.trim ? s.trim() : s;
1908
return s.replace(TRIMREGEX, '');
1915
* Returns a string without any leading whitespace.
1918
* @param s {string} the string to trim.
1919
* @return {string} the trimmed string.
1921
L.trimLeft = STRING_PROTO.trimLeft ? function (s) {
1922
return s.trimLeft();
1924
return s.replace(/^\s+/, '');
1928
* Returns a string without any trailing whitespace.
1931
* @param s {string} the string to trim.
1932
* @return {string} the trimmed string.
1934
L.trimRight = STRING_PROTO.trimRight ? function (s) {
1935
return s.trimRight();
1937
return s.replace(/\s+$/, '');
1941
* A convenience method for detecting a legitimate non-null value.
1942
* Returns false for null/undefined/NaN, true for other values,
1943
* including 0/false/''
1946
* @param o The item to test.
1947
* @return {boolean} true if it is not null/undefined/NaN || false.
1949
L.isValue = function(o) {
1956
case 'null': // fallthru
1967
* Returns a string representing the type of the item passed in.
1976
* <code>typeof HTMLElementCollection</code> returns function in Safari, but
1977
* <code>Y.type()</code> reports object, which could be a good thing --
1978
* but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
1983
* @param o the item to test.
1984
* @return {string} the detected type.
1987
L.type = function(o) {
1988
return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
1992
* Lightweight version of <code>Y.substitute</code>. Uses the same template
1993
* structure as <code>Y.substitute</code>, but doesn't support recursion,
1994
* auto-object coersion, or formats.
1996
* @param {string} s String to be modified.
1997
* @param {object} o Object containing replacement values.
1998
* @return {string} the substitute result.
2002
L.sub = function(s, o) {
2003
return s.replace ? s.replace(SUBREGEX, function (match, key) {
2004
return L.isUndefined(o[key]) ? match : o[key];
2009
* Returns the current time in milliseconds.
2012
* @return {Number} Current time in milliseconds.
2016
L.now = Date.now || function () {
2017
return new Date().getTime();
2020
* The YUI module contains the components required for building the YUI seed
2021
* file. This includes the script loading mechanism, a simple queue, and the
2022
* core utilities for the library.
2025
* @submodule yui-base
2029
Native = Array.prototype,
2031
hasOwn = Object.prototype.hasOwnProperty;
2034
Provides utility methods for working with arrays. Additional array helpers can
2035
be found in the `collection` and `array-extras` modules.
2037
`Y.Array(thing)` returns a native array created from _thing_. Depending on
2038
_thing_'s type, one of the following will happen:
2040
* Arrays are returned unmodified unless a non-zero _startIndex_ is
2042
* Array-like collections (see `Array.test()`) are converted to arrays.
2043
* For everything else, a new array is created with _thing_ as the sole
2046
Note: elements that are also collections, such as `<form>` and `<select>`
2047
elements, are not automatically converted to arrays. To force a conversion,
2048
pass `true` as the value of the _force_ parameter.
2052
@param {Any} thing The thing to arrayify.
2053
@param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like
2054
collection, a subset of items starting at the specified index will be
2056
@param {Boolean} [force=false] If `true`, _thing_ will be treated as an
2057
array-like collection no matter what.
2058
@return {Array} A native array created from _thing_, according to the rules
2061
function YArray(thing, startIndex, force) {
2064
startIndex || (startIndex = 0);
2066
if (force || YArray.test(thing)) {
2067
// IE throws when trying to slice HTMLElement collections.
2069
return Native.slice.call(thing, startIndex);
2073
for (len = thing.length; startIndex < len; ++startIndex) {
2074
result.push(thing[startIndex]);
2087
Evaluates _obj_ to determine if it's an array, an array-like collection, or
2088
something else. This is useful when working with the function `arguments`
2089
collection and `HTMLElement` collections.
2091
Note: This implementation doesn't consider elements that are also
2092
collections, such as `<form>` and `<select>`, to be array-like.
2095
@param {Object} obj Object to test.
2096
@return {Number} A number indicating the results of the test:
2098
* 0: Neither an array nor an array-like collection.
2100
* 2: Array-like collection.
2104
YArray.test = function (obj) {
2107
if (Lang.isArray(obj)) {
2109
} else if (Lang.isObject(obj)) {
2111
// indexed, but no tagName (element) or alert (window),
2112
// or functions without apply/call (Safari
2113
// HTMLElementCollection bug).
2114
if ('length' in obj && !obj.tagName && !obj.alert && !obj.apply) {
2124
Dedupes an array of strings, returning an array that's guaranteed to contain
2125
only one copy of a given string.
2127
This method differs from `Array.unique()` in that it's optimized for use only
2128
with strings, whereas `unique` may be used with other types (but is slower).
2129
Using `dedupe()` with non-string values may result in unexpected behavior.
2132
@param {String[]} array Array of strings to dedupe.
2133
@return {Array} Deduped copy of _array_.
2137
YArray.dedupe = function (array) {
2142
for (i = 0, len = array.length; i < len; ++i) {
2145
if (!hasOwn.call(hash, item)) {
2155
Executes the supplied function on each item in the array. This method wraps
2156
the native ES5 `Array.forEach()` method if available.
2159
@param {Array} array Array to iterate.
2160
@param {Function} fn Function to execute on each item in the array. The function
2161
will receive the following arguments:
2162
@param {Any} fn.item Current array item.
2163
@param {Number} fn.index Current array index.
2164
@param {Array} fn.array Array being iterated.
2165
@param {Object} [thisObj] `this` object to use when calling _fn_.
2166
@return {YUI} The YUI instance.
2169
YArray.each = YArray.forEach = Native.forEach ? function (array, fn, thisObj) {
2170
Native.forEach.call(array || [], fn, thisObj || Y);
2172
} : function (array, fn, thisObj) {
2173
for (var i = 0, len = (array && array.length) || 0; i < len; ++i) {
2175
fn.call(thisObj || Y, array[i], i, array);
2190
Returns an object using the first array as keys and the second as values. If
2191
the second array is not provided, or if it doesn't contain the same number of
2192
values as the first array, then `true` will be used in place of the missing
2197
Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']);
2198
// => {a: 'foo', b: 'bar', c: true}
2201
@param {String[]} keys Array of strings to use as keys.
2202
@param {Array} [values] Array to use as values.
2203
@return {Object} Hash using the first array as keys and the second as values.
2206
YArray.hash = function (keys, values) {
2208
vlen = (values && values.length) || 0,
2211
for (i = 0, len = keys.length; i < len; ++i) {
2213
hash[keys[i]] = vlen > i && i in values ? values[i] : true;
2221
Returns the index of the first item in the array that's equal (using a strict
2222
equality check) to the specified _value_, or `-1` if the value isn't found.
2224
This method wraps the native ES5 `Array.indexOf()` method if available.
2227
@param {Array} array Array to search.
2228
@param {Any} value Value to search for.
2229
@return {Number} Index of the item strictly equal to _value_, or `-1` if not
2233
YArray.indexOf = Native.indexOf ? function (array, value) {
2234
// TODO: support fromIndex
2235
return Native.indexOf.call(array, value);
2236
} : function (array, value) {
2237
for (var i = 0, len = array.length; i < len; ++i) {
2238
if (array[i] === value) {
2247
Numeric sort convenience function.
2249
The native `Array.prototype.sort()` function converts values to strings and
2250
sorts them in lexicographic order, which is unsuitable for sorting numeric
2251
values. Provide `Array.numericSort` as a custom sort function when you want
2252
to sort values in numeric order.
2256
[42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort);
2257
// => [4, 8, 15, 16, 23, 42]
2260
@param {Number} a First value to compare.
2261
@param {Number} b Second value to compare.
2262
@return {Number} Difference between _a_ and _b_.
2265
YArray.numericSort = function (a, b) {
2270
Executes the supplied function on each item in the array. Returning a truthy
2271
value from the function will stop the processing of remaining items.
2274
@param {Array} array Array to iterate over.
2275
@param {Function} fn Function to execute on each item. The function will receive
2276
the following arguments:
2277
@param {Any} fn.value Current array item.
2278
@param {Number} fn.index Current array index.
2279
@param {Array} fn.array Array being iterated over.
2280
@param {Object} [thisObj] `this` object to use when calling _fn_.
2281
@return {Boolean} `true` if the function returns a truthy value on any of the
2282
items in the array; `false` otherwise.
2285
YArray.some = Native.some ? function (array, fn, thisObj) {
2286
return Native.some.call(array, fn, thisObj);
2287
} : function (array, fn, thisObj) {
2288
for (var i = 0, len = array.length; i < len; ++i) {
2289
if (i in array && fn.call(thisObj, array[i], i, array)) {
2297
* The YUI module contains the components required for building the YUI
2298
* seed file. This includes the script loading mechanism, a simple queue,
2299
* and the core utilities for the library.
2301
* @submodule yui-base
2305
* A simple FIFO queue. Items are added to the Queue with add(1..n items) and
2306
* removed using next().
2310
* @param {MIXED} item* 0..n items to seed the queue.
2314
this.add.apply(this, arguments);
2319
* Initialize the queue
2326
* The collection of enqueued items
2336
* Get the next item in the queue. FIFO support
2339
* @return {MIXED} the next item in the queue.
2342
return this._q.shift();
2346
* Get the last in the queue. LIFO support.
2349
* @return {MIXED} the last item in the queue.
2352
return this._q.pop();
2356
* Add 0..n items to the end of the queue.
2359
* @param {MIXED} item* 0..n items.
2360
* @return {object} this queue.
2363
this._q.push.apply(this._q, arguments);
2369
* Returns the current number of queued items.
2372
* @return {Number} The size.
2375
return this._q.length;
2381
YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
2384
The YUI module contains the components required for building the YUI seed file.
2385
This includes the script loading mechanism, a simple queue, and the core
2386
utilities for the library.
2392
var CACHED_DELIMITER = '__',
2394
hasOwn = Object.prototype.hasOwnProperty,
2395
isObject = Y.Lang.isObject;
2398
Returns a wrapper for a function which caches the return value of that function,
2399
keyed off of the combined string representation of the argument values provided
2400
when the wrapper is called.
2402
Calling this function again with the same arguments will return the cached value
2403
rather than executing the wrapped function.
2405
Note that since the cache is keyed off of the string representation of arguments
2406
passed to the wrapper function, arguments that aren't strings and don't provide
2407
a meaningful `toString()` method may result in unexpected caching behavior. For
2408
example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
2409
string `[object Object]` when used as a cache key.
2412
@param {Function} source The function to memoize.
2413
@param {Object} [cache={}] Object in which to store cached values. You may seed
2414
this object with pre-existing cached values if desired.
2415
@param {any} [refetch] If supplied, this value is compared with the cached value
2416
using a `==` comparison. If the values are equal, the wrapped function is
2417
executed again even though a cached value exists.
2418
@return {Function} Wrapped function.
2421
Y.cached = function (source, cache, refetch) {
2422
cache || (cache = {});
2424
return function (arg) {
2425
var key = arguments.length > 1 ?
2426
Array.prototype.join.call(arguments, CACHED_DELIMITER) :
2429
if (!(key in cache) || (refetch && cache[key] == refetch)) {
2430
cache[key] = source.apply(source, arguments);
2438
Returns a new object containing all of the properties of all the supplied
2439
objects. The properties from later objects will overwrite those in earlier
2442
Passing in a single object will create a shallow copy of it. For a deep copy,
2446
@param {Object} objects* One or more objects to merge.
2447
@return {Object} A new merged object.
2449
Y.merge = function () {
2450
var args = arguments,
2455
for (; i < len; ++i) {
2456
Y.mix(result, args[i], true);
2463
Mixes _supplier_'s properties into _receiver_. Properties will not be
2464
overwritten or merged unless the _overwrite_ or _merge_ parameters are `true`,
2467
In the default mode (0), only properties the supplier owns are copied (prototype
2468
properties are not copied). The following copying modes are available:
2470
* `0`: _Default_. Object to object.
2471
* `1`: Prototype to prototype.
2472
* `2`: Prototype to prototype and object to object.
2473
* `3`: Prototype to object.
2474
* `4`: Object to prototype.
2477
@param {Function|Object} receiver The object or function to receive the mixed
2479
@param {Function|Object} supplier The object or function supplying the
2480
properties to be mixed.
2481
@param {Boolean} [overwrite=false] If `true`, properties that already exist
2482
on the receiver will be overwritten with properties from the supplier.
2483
@param {String[]} [whitelist] An array of property names to copy. If
2484
specified, only the whitelisted properties will be copied, and all others
2486
@param {Int} [mode=0] Mix mode to use. See above for available modes.
2487
@param {Boolean} [merge=false] If `true`, objects and arrays that already
2488
exist on the receiver will have the corresponding object/array from the
2489
supplier merged into them, rather than being skipped or overwritten. When
2490
both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
2491
@return {Function|Object|YUI} The receiver, or the YUI instance if the
2492
specified receiver is falsy.
2494
Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
2495
var alwaysOverwrite, exists, from, i, key, len, to;
2497
// If no supplier is given, we return the receiver. If no receiver is given,
2498
// we return Y. Returning Y doesn't make much sense to me, but it's
2499
// grandfathered in for backcompat reasons.
2500
if (!receiver || !supplier) {
2501
return receiver || Y;
2505
// In mode 2 (prototype to prototype and object to object), we recurse
2506
// once to do the proto to proto mix. The object to object mix will be
2507
// handled later on.
2509
Y.mix(receiver.prototype, supplier.prototype, overwrite,
2510
whitelist, 0, merge);
2513
// Depending on which mode is specified, we may be copying from or to
2514
// the prototypes of the supplier and receiver.
2515
from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
2516
to = mode === 1 || mode === 4 ? receiver.prototype : receiver;
2518
// If either the supplier or receiver doesn't actually have a
2519
// prototype property, then we could end up with an undefined `from`
2520
// or `to`. If that happens, we abort and return the receiver.
2529
// If `overwrite` is truthy and `merge` is falsy, then we can skip a call
2530
// to `hasOwnProperty` on each iteration and save some time.
2531
alwaysOverwrite = overwrite && !merge;
2534
for (i = 0, len = whitelist.length; i < len; ++i) {
2537
// We call `Object.prototype.hasOwnProperty` instead of calling
2538
// `hasOwnProperty` on the object itself, since the object's
2539
// `hasOwnProperty` method may have been overridden or removed.
2540
// Also, some native objects don't implement a `hasOwnProperty`
2542
if (!hasOwn.call(from, key)) {
2546
exists = alwaysOverwrite ? false : hasOwn.call(to, key);
2548
if (merge && exists && isObject(to[key], true)
2549
&& isObject(from[key], true)) {
2550
// If we're in merge mode, and the key is present on both
2551
// objects, and the value on both objects is either an object or
2552
// an array (but not a function), then we recurse to merge the
2553
// `from` value into the `to` value instead of overwriting it.
2555
// Note: It's intentional that the whitelist isn't passed to the
2556
// recursive call here. This is legacy behavior that lots of
2557
// code still depends on.
2558
Y.mix(to[key], from[key], overwrite, null, 0, merge);
2559
} else if (overwrite || !exists) {
2560
// We're not in merge mode, so we'll only copy the `from` value
2561
// to the `to` value if we're in overwrite mode or if the
2562
// current key doesn't exist on the `to` object.
2563
to[key] = from[key];
2568
// The code duplication here is for runtime performance reasons.
2569
// Combining whitelist and non-whitelist operations into a single
2570
// loop or breaking the shared logic out into a function both result
2571
// in worse performance, and Y.mix is critical enough that the byte
2572
// tradeoff is worth it.
2573
if (!hasOwn.call(from, key)) {
2577
exists = alwaysOverwrite ? false : hasOwn.call(to, key);
2579
if (merge && exists && isObject(to[key], true)
2580
&& isObject(from[key], true)) {
2581
Y.mix(to[key], from[key], overwrite, null, 0, merge);
2582
} else if (overwrite || !exists) {
2583
to[key] = from[key];
2587
// If this is an IE browser with the JScript enumeration bug, force
2588
// enumeration of the buggy properties by making a recursive call with
2589
// the buggy properties as the whitelist.
2590
if (Y.Object._hasEnumBug) {
2591
Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
2598
* The YUI module contains the components required for building the YUI
2599
* seed file. This includes the script loading mechanism, a simple queue,
2600
* and the core utilities for the library.
2602
* @submodule yui-base
2606
* Adds utilities to the YUI instance for working with objects.
2611
var hasOwn = Object.prototype.hasOwnProperty,
2613
// If either MooTools or Prototype is on the page, then there's a chance that we
2614
// can't trust "native" language features to actually be native. When this is
2615
// the case, we take the safe route and fall back to our own non-native
2618
unsafeNatives = win && !!(win.MooTools || win.Prototype),
2620
UNDEFINED, // <-- Note the comma. We're still declaring vars.
2623
* Returns a new object that uses _obj_ as its prototype. This method wraps the
2624
* native ES5 `Object.create()` method if available, but doesn't currently
2625
* pass through `Object.create()`'s second argument (properties) in order to
2626
* ensure compatibility with older browsers.
2629
* @param {Object} obj Prototype object.
2630
* @return {Object} New object using _obj_ as its prototype.
2633
O = Y.Object = (!unsafeNatives && Object.create) ? function (obj) {
2634
// We currently wrap the native Object.create instead of simply aliasing it
2635
// to ensure consistency with our fallback shim, which currently doesn't
2636
// support Object.create()'s second argument (properties). Once we have a
2637
// safe fallback for the properties arg, we can stop wrapping
2639
return Object.create(obj);
2641
// Reusable constructor function for the Object.create() shim.
2645
return function (obj) {
2652
* Property names that IE doesn't enumerate in for..in loops, even when they
2653
* should be enumerable. When `_hasEnumBug` is `true`, it's necessary to
2654
* manually enumerate these properties.
2656
* @property _forceEnum
2661
forceEnum = O._forceEnum = [
2664
'propertyIsEnumerable',
2671
* `true` if this browser has the JScript enumeration bug that prevents
2672
* enumeration of the properties named in the `_forceEnum` array, `false`
2676
* - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug>
2677
* - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation>
2679
* @property _hasEnumBug
2684
hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'),
2687
* Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or
2688
* exists only on _obj_'s prototype. This is essentially a safer version of
2689
* `obj.hasOwnProperty()`.
2692
* @param {Object} obj Object to test.
2693
* @param {String} key Property name to look for.
2694
* @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2697
owns = O.owns = function (obj, key) {
2698
return !!obj && hasOwn.call(obj, key);
2699
}; // <-- End of var declarations.
2702
* Alias for `owns()`.
2705
* @param {Object} obj Object to test.
2706
* @param {String} key Property name to look for.
2707
* @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
2713
* Returns an array containing the object's enumerable keys. Does not include
2714
* prototype keys or non-enumerable keys.
2716
* Note that keys are returned in enumeration order (that is, in the same order
2717
* that they would be enumerated by a `for-in` loop), which may not be the same
2718
* as the order in which they were defined.
2720
* This method is an alias for the native ES5 `Object.keys()` method if
2725
* Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'});
2726
* // => ['a', 'b', 'c']
2729
* @param {Object} obj An object.
2730
* @return {String[]} Array of keys.
2733
O.keys = (!unsafeNatives && Object.keys) || function (obj) {
2734
if (!Y.Lang.isObject(obj)) {
2735
throw new TypeError('Object.keys called on a non-object');
2742
if (owns(obj, key)) {
2748
for (i = 0, len = forceEnum.length; i < len; ++i) {
2751
if (owns(obj, key)) {
2761
* Returns an array containing the values of the object's enumerable keys.
2763
* Note that values are returned in enumeration order (that is, in the same
2764
* order that they would be enumerated by a `for-in` loop), which may not be the
2765
* same as the order in which they were defined.
2769
* Y.Object.values({a: 'foo', b: 'bar', c: 'baz'});
2770
* // => ['foo', 'bar', 'baz']
2773
* @param {Object} obj An object.
2774
* @return {Array} Array of values.
2777
O.values = function (obj) {
2778
var keys = O.keys(obj),
2783
for (; i < len; ++i) {
2784
values.push(obj[keys[i]]);
2791
* Returns the number of enumerable keys owned by an object.
2794
* @param {Object} obj An object.
2795
* @return {Number} The object's size.
2798
O.size = function (obj) {
2799
return O.keys(obj).length;
2803
* Returns `true` if the object owns an enumerable property with the specified
2807
* @param {Object} obj An object.
2808
* @param {any} value The value to search for.
2809
* @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise.
2812
O.hasValue = function (obj, value) {
2813
return Y.Array.indexOf(O.values(obj), value) > -1;
2817
* Executes a function on each enumerable property in _obj_. The function
2818
* receives the value, the key, and the object itself as parameters (in that
2821
* By default, only properties owned by _obj_ are enumerated. To include
2822
* prototype properties, set the _proto_ parameter to `true`.
2825
* @param {Object} obj Object to enumerate.
2826
* @param {Function} fn Function to execute on each enumerable property.
2827
* @param {mixed} fn.value Value of the current property.
2828
* @param {String} fn.key Key of the current property.
2829
* @param {Object} fn.obj Object being enumerated.
2830
* @param {Object} [thisObj] `this` object to use when calling _fn_.
2831
* @param {Boolean} [proto=false] Include prototype properties.
2832
* @return {YUI} the YUI instance.
2836
O.each = function (obj, fn, thisObj, proto) {
2840
if (proto || owns(obj, key)) {
2841
fn.call(thisObj || Y, obj[key], key, obj);
2849
* Executes a function on each enumerable property in _obj_, but halts if the
2850
* function returns a truthy value. The function receives the value, the key,
2851
* and the object itself as paramters (in that order).
2853
* By default, only properties owned by _obj_ are enumerated. To include
2854
* prototype properties, set the _proto_ parameter to `true`.
2857
* @param {Object} obj Object to enumerate.
2858
* @param {Function} fn Function to execute on each enumerable property.
2859
* @param {mixed} fn.value Value of the current property.
2860
* @param {String} fn.key Key of the current property.
2861
* @param {Object} fn.obj Object being enumerated.
2862
* @param {Object} [thisObj] `this` object to use when calling _fn_.
2863
* @param {Boolean} [proto=false] Include prototype properties.
2864
* @return {Boolean} `true` if any execution of _fn_ returns a truthy value,
2865
* `false` otherwise.
2868
O.some = function (obj, fn, thisObj, proto) {
2872
if (proto || owns(obj, key)) {
2873
if (fn.call(thisObj || Y, obj[key], key, obj)) {
2883
* Retrieves the sub value at the provided path,
2884
* from the value object provided.
2888
* @param o The object from which to extract the property value.
2889
* @param path {Array} A path array, specifying the object traversal path
2890
* from which to obtain the sub value.
2891
* @return {Any} The value stored in the path, undefined if not found,
2892
* undefined if the source is not an object. Returns the source object
2893
* if an empty path is provided.
2895
O.getValue = function(o, path) {
2896
if (!Y.Lang.isObject(o)) {
2904
for (i = 0; o !== UNDEFINED && i < l; i++) {
2912
* Sets the sub-attribute value at the provided path on the
2913
* value object. Returns the modified value object, or
2914
* undefined if the path is invalid.
2918
* @param o The object on which to set the sub value.
2919
* @param path {Array} A path array, specifying the object traversal path
2920
* at which to set the sub value.
2921
* @param val {Any} The new value for the sub-attribute.
2922
* @return {Object} The modified object, with the new sub value set, or
2923
* undefined, if the path was invalid.
2925
O.setValue = function(o, path, val) {
2928
leafIdx = p.length - 1,
2932
for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) {
2936
if (ref !== UNDEFINED) {
2947
* Returns `true` if the object has no enumerable properties of its own.
2950
* @param {Object} obj An object.
2951
* @return {Boolean} `true` if the object is empty.
2955
O.isEmpty = function (obj) {
2956
return !O.keys(obj).length;
2959
* The YUI module contains the components required for building the YUI seed
2960
* file. This includes the script loading mechanism, a simple queue, and the
2961
* core utilities for the library.
2963
* @submodule yui-base
2967
* YUI user agent detection.
2968
* Do not fork for a browser if it can be avoided. Use feature detection when
2969
* you can. Use the user agent as a last resort. For all fields listed
2970
* as @type float, UA stores a version number for the browser engine,
2971
* 0 otherwise. This value may or may not map to the version number of
2972
* the browser using the engine. The value is presented as a float so
2973
* that it can easily be used for boolean evaluation as well as for
2974
* looking for a particular range of versions. Because of this,
2975
* some of the granularity of the version info may be lost. The fields that
2976
* are @type string default to null. The API docs list the values that
2977
* these fields can have.
2982
* Static method for parsing the UA string. Defaults to assigning it's value to Y.UA
2984
* @method Env.parseUA
2985
* @param {String} subUA Parse this UA string instead of navigator.userAgent
2986
* @returns {Object} The Y.UA object
2988
YUI.Env.parseUA = function(subUA) {
2990
var numberify = function(s) {
2992
return parseFloat(s.replace(/\./g, function() {
2993
return (c++ == 1) ? '' : '.';
2999
nav = win && win.navigator,
3004
* Internet Explorer version number or 0. Example: 6
3012
* Opera version number or 0. Example: 9.2
3020
* Gecko engine revision number. Will evaluate to 1 if Gecko
3021
* is detected but the revision could not be found. Other browsers
3022
* will be 0. Example: 1.8
3024
* Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7
3025
* Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
3026
* Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
3027
* Firefox 3.0 <-- 1.9
3028
* Firefox 3.5 <-- 1.91
3037
* AppleWebKit version. KHTML browsers that are not WebKit browsers
3038
* will evaluate to 1, other browsers 0. Example: 418.9
3040
* Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
3041
* latest available for Mac OSX 10.3.
3042
* Safari 2.0.2: 416 <-- hasOwnProperty introduced
3043
* Safari 2.0.4: 418 <-- preventDefault fixed
3044
* Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
3045
* different versions of webkit
3046
* Safari 2.0.4 (419.3): 419 <-- Tiger installations that have been
3047
* updated, but not updated
3048
* to the latest patch.
3049
* Webkit 212 nightly: 522+ <-- Safari 3.0 precursor (with native
3050
* SVG and many major issues fixed).
3051
* Safari 3.0.4 (523.12) 523.12 <-- First Tiger release - automatic
3052
* update from 2.x via the 10.4.11 OS patch.
3053
* Webkit nightly 1/2008:525+ <-- Supports DOMContentLoaded event.
3054
* yahoo.com user agent hack removed.
3056
* http://en.wikipedia.org/wiki/Safari_version_history
3064
* Safari will be detected as webkit, but this property will also
3065
* be populated with the Safari version number
3073
* Chrome will be detected as webkit, but this property will also
3074
* be populated with the Chrome version number
3082
* The mobile property will be set to a string containing any relevant
3083
* user agent information when a modern mobile browser is detected.
3084
* Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
3085
* devices with the WebKit-based browser, and Opera Mini.
3094
* Adobe AIR version number or 0. Only populated if webkit is detected.
3101
* Detects Apple iPad's OS version
3108
* Detects Apple iPhone's OS version
3115
* Detects Apples iPod's OS version
3122
* General truthy check for iPad, iPhone or iPod
3130
* Detects Googles Android OS version
3137
* Detects Palms WebOS version
3145
* Google Caja version number or 0.
3149
caja: nav && nav.cajaVersion,
3152
* Set to true if the page appears to be in SSL
3160
* The operating system. Currently only detecting windows or macintosh
3170
ua = subUA || nav && nav.userAgent,
3172
loc = win && win.location,
3174
href = loc && loc.href,
3178
o.secure = href && (href.toLowerCase().indexOf('https') === 0);
3182
if ((/windows|win32/i).test(ua)) {
3184
} else if ((/macintosh/i).test(ua)) {
3186
} else if ((/rhino/i).test(ua)) {
3190
// Modern KHTML browsers should qualify as Safari X-Grade
3191
if ((/KHTML/).test(ua)) {
3194
// Modern WebKit browsers are at least X-Grade
3195
m = ua.match(/AppleWebKit\/([^\s]*)/);
3197
o.webkit = numberify(m[1]);
3198
o.safari = o.webkit;
3200
// Mobile browser check
3201
if (/ Mobile\//.test(ua)) {
3202
o.mobile = 'Apple'; // iPhone or iPod Touch
3204
m = ua.match(/OS ([^\s]*)/);
3206
m = numberify(m[1].replace('_', '.'));
3209
o.ipad = o.ipod = o.iphone = 0;
3211
m = ua.match(/iPad|iPod|iPhone/);
3213
o[m[0].toLowerCase()] = o.ios;
3216
m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/);
3218
// Nokia N-series, webOS, ex: NokiaN95
3221
if (/webOS/.test(ua)) {
3223
m = ua.match(/webOS\/([^\s]*);/);
3225
o.webos = numberify(m[1]);
3228
if (/ Android/.test(ua)) {
3229
if (/Mobile/.test(ua)) {
3230
o.mobile = 'Android';
3232
m = ua.match(/Android ([^\s]*);/);
3234
o.android = numberify(m[1]);
3240
m = ua.match(/Chrome\/([^\s]*)/);
3242
o.chrome = numberify(m[1]); // Chrome
3243
o.safari = 0; //Reset safari back to 0
3245
m = ua.match(/AdobeAIR\/([^\s]*)/);
3247
o.air = m[0]; // Adobe AIR 1.0 or better
3252
if (!o.webkit) { // not webkit
3253
// @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
3254
m = ua.match(/Opera[\s\/]([^\s]*)/);
3256
o.opera = numberify(m[1]);
3257
m = ua.match(/Version\/([^\s]*)/);
3259
o.opera = numberify(m[1]); // opera 10+
3262
m = ua.match(/Opera Mini[^;]*/);
3265
o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
3267
} else { // not opera or webkit
3268
m = ua.match(/MSIE\s([^;]*)/);
3270
o.ie = numberify(m[1]);
3271
} else { // not opera, webkit, or ie
3272
m = ua.match(/Gecko\/([^\s]*)/);
3274
o.gecko = 1; // Gecko detected, look for revision
3275
m = ua.match(/rv:([^\s\)]*)/);
3277
o.gecko = numberify(m[1]);
3291
Y.UA = YUI.Env.UA || YUI.Env.parseUA();
3293
"anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"],
3294
"app": ["controller","model","model-list","view"],
3295
"attribute": ["attribute-base","attribute-complex"],
3296
"autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"],
3297
"base": ["base-base","base-pluginhost","base-build"],
3298
"cache": ["cache-base","cache-offline","cache-plugin"],
3299
"collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"],
3300
"dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"],
3301
"datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"],
3302
"datatable": ["datatable-base","datatable-datasource","datatable-sort","datatable-scroll"],
3303
"datatype": ["datatype-number","datatype-date","datatype-xml"],
3304
"datatype-date": ["datatype-date-parse","datatype-date-format"],
3305
"datatype-number": ["datatype-number-parse","datatype-number-format"],
3306
"datatype-xml": ["datatype-xml-parse","datatype-xml-format"],
3307
"dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"],
3308
"dom": ["dom-base","dom-screen","dom-style","selector-native","selector"],
3309
"editor": ["frame","selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"],
3310
"event": ["event-base","event-delegate","event-synthetic","event-mousewheel","event-mouseenter","event-key","event-focus","event-resize","event-hover","event-outside"],
3311
"event-custom": ["event-custom-base","event-custom-complex"],
3312
"event-gestures": ["event-flick","event-move"],
3313
"highlight": ["highlight-base","highlight-accentfold"],
3314
"history": ["history-base","history-hash","history-hash-ie","history-html5"],
3315
"io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"],
3316
"json": ["json-parse","json-stringify"],
3317
"loader": ["loader-base","loader-rollup","loader-yui3"],
3318
"node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"],
3319
"pluginhost": ["pluginhost-base","pluginhost-config"],
3320
"querystring": ["querystring-parse","querystring-stringify"],
3321
"recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"],
3322
"resize": ["resize-base","resize-proxy","resize-constrain"],
3323
"slider": ["slider-base","slider-value-range","clickable-rail","range-slider"],
3324
"text": ["text-accentfold","text-wordbreak"],
3325
"widget": ["widget-base","widget-htmlparser","widget-uievents","widget-skin"]
3330
YUI.add('get', function(Y) {
3333
* Provides a mechanism to fetch remote resources and
3334
* insert them into a document.
3340
* Fetches and inserts one or more script or link nodes into the document
3347
TYPE_JS = 'text/javascript',
3348
TYPE_CSS = 'text/css',
3349
STYLESHEET = 'stylesheet',
3351
AUTOPURGE = 'autopurge',
3357
// FireFox does not support the onload event for link nodes, so
3358
// there is no way to make the css requests synchronous. This means
3359
// that the css rules in multiple files could be applied out of order
3360
// in this browser if a later request returns before an earlier one.
3364
ONLOAD_SUPPORTED = {
3366
css: !(ua.webkit || ua.gecko)
3370
* hash of queues to manage multiple requests
3377
* queue index used to generate transaction ids
3385
* interal property used to prevent multiple simultaneous purge
3394
* Clear timeout state
3396
* @method _clearTimeout
3397
* @param {Object} q Queue data
3400
_clearTimeout = function(q) {
3401
var timer = q.timer;
3403
clearTimeout(timer);
3409
* Generates an HTML element, this is not appended to a document
3411
* @param {string} type the type of element.
3412
* @param {Object} attr the fixed set of attribute for the type.
3413
* @param {Object} custAttrs optional Any custom attributes provided by the user.
3414
* @param {Window} win optional window to create the element in.
3415
* @return {HTMLElement} the generated node.
3418
_node = function(type, attr, custAttrs, win) {
3419
var w = win || Y.config.win,
3421
n = d.createElement(type),
3425
Y.mix(attr, custAttrs);
3429
if (attr[i] && attr.hasOwnProperty(i)) {
3430
n.setAttribute(i, attr[i]);
3438
* Generates a link node
3440
* @param {string} url the url for the css file.
3441
* @param {Window} win optional window to create the node in.
3442
* @param {object} attributes optional attributes collection to apply to the
3444
* @return {HTMLElement} the generated node.
3447
_linkNode = function(url, win, attributes) {
3448
return _node(LINK, {
3453
}, attributes, win);
3457
* Generates a script node
3458
* @method _scriptNode
3459
* @param {string} url the url for the script file.
3460
* @param {Window} win optional window to create the node in.
3461
* @param {object} attributes optional attributes collection to apply to the
3463
* @return {HTMLElement} the generated node.
3466
_scriptNode = function(url, win, attributes) {
3467
return _node(SCRIPT, {
3471
}, attributes, win);
3475
* Returns the data payload for callback functions.
3476
* @method _returnData
3477
* @param {object} q the queue.
3478
* @param {string} msg the result message.
3479
* @param {string} result the status message from the request.
3480
* @return {object} the state data from the request.
3483
_returnData = function(q, msg, result) {
3499
* The transaction is finished
3501
* @param {string} id the id of the request.
3502
* @param {string} msg the result message.
3503
* @param {string} result the status message from the request.
3506
_end = function(id, msg, result) {
3508
onEnd = q && q.onEnd;
3513
onEnd.call(q.context, _returnData(q, msg, result));
3518
* The request failed, execute fail handler with whatever
3519
* was accomplished. There isn't a failure case at the
3520
* moment unless you count aborted transactions
3522
* @param {string} id the id of the request
3525
_fail = function(id, msg) {
3526
Y.log('get failure: ' + msg, 'warn', 'get');
3529
onFailure = q.onFailure;
3534
onFailure.call(q.context, _returnData(q, msg));
3537
_end(id, msg, 'failure');
3542
* Abort the transaction
3545
* @param {Object} id
3548
_abort = function(id) {
3549
_fail(id, 'transaction ' + id + ' was aborted');
3553
* The request is complete, so executing the requester's callback
3555
* @param {string} id the id of the request.
3558
_complete = function(id) {
3559
Y.log("Finishing transaction " + id, "info", "get");
3562
onSuccess = q.onSuccess;
3571
onSuccess.call(q.context, _returnData(q));
3574
// 3.3.0 had undefined msg for this path.
3575
_end(id, undefined, 'OK');
3580
* Get node reference, from string
3582
* @method _getNodeRef
3583
* @param {String|HTMLElement} nId The node id to find. If an HTMLElement is passed in, it will be returned.
3584
* @param {String} tId Queue id, used to determine document for queue
3587
_getNodeRef = function(nId, tId) {
3588
var q = queues[tId],
3589
n = (L.isString(nId)) ? q.win.document.getElementById(nId) : nId;
3591
_fail(tId, 'target node not found: ' + nId);
3598
* Removes the nodes for the specified queue
3600
* @param {string} tId the transaction id.
3603
_purge = function(tId) {
3604
var nodes, doc, parent, sibling, node, attr, insertBefore,
3612
// TODO: Why is node.parentNode undefined? Which forces us to do this...
3614
doc = q.win.document;
3615
parent = doc.getElementsByTagName('head')[0];
3616
insertBefore = q.insertBefore || doc.getElementsByTagName('base')[0];
3619
sibling = _getNodeRef(insertBefore, tId);
3621
parent = sibling.parentNode;
3626
for (i = 0; i < l; i++) {
3628
parent = node.parentNode;
3630
if (node.clearAttributes) {
3631
node.clearAttributes();
3633
// This destroys parentNode ref, so we hold onto it above first.
3634
for (attr in node) {
3635
if (node.hasOwnProperty(attr)) {
3641
parent.removeChild(node);
3652
* @param {string} id The id of the request.
3653
* @param {string} The url which just completed.
3656
_progress = function(id, url) {
3658
onProgress = q.onProgress,
3664
onProgress.call(q.context, o);
3671
* @param {string} id the id of the request.
3674
_timeout = function(id) {
3675
Y.log('Timeout ' + id, 'info', 'get');
3678
onTimeout = q.onTimeout;
3681
onTimeout.call(q.context, _returnData(q));
3684
_end(id, 'timeout', 'timeout');
3690
* @param {string} id the id of the request.
3691
* @return {string} the result.
3694
_loaded = function(id, url) {
3697
sync = (q && !q.async);
3709
// TODO: Cleaning up flow to have a consistent end point
3711
// !q.finished check is for the async case,
3712
// where scripts may still be loading when we've
3713
// already aborted. Ideally there should be a single path
3720
if ((--q.remaining) === 0) {
3730
* Detects when a node has been loaded. In the case of
3731
* script nodes, this does not guarantee that contained
3732
* script is ready to use.
3733
* @method _trackLoad
3734
* @param {string} type the type of node to track.
3735
* @param {HTMLElement} n the node to track.
3736
* @param {string} id the id of the request.
3737
* @param {string} url the url that is being loaded.
3740
_trackLoad = function(type, n, id, url) {
3742
// TODO: Can we massage this to use ONLOAD_SUPPORTED[type]?
3744
// IE supports the readystatechange event for script and css nodes
3745
// Opera only for script nodes. Opera support onload for script
3746
// nodes, but this doesn't fire when there is a load failure.
3747
// The onreadystatechange appears to be a better way to respond
3748
// to both success and failure.
3752
n.onreadystatechange = function() {
3753
var rs = this.readyState;
3754
if ('loaded' === rs || 'complete' === rs) {
3755
// Y.log(id + " onreadstatechange " + url, "info", "get");
3756
n.onreadystatechange = null;
3761
} else if (ua.webkit) {
3763
// webkit prior to 3.x is no longer supported
3764
if (type === SCRIPT) {
3765
// Safari 3.x supports the load event for script nodes (DOM2)
3766
n.addEventListener('load', function() {
3773
// FireFox and Opera support onload (but not DOM2 in FF) handlers for
3774
// script nodes. Opera, but not FF, supports the onload event for link nodes.
3776
n.onload = function() {
3777
// Y.log(id + " onload " + url, "info", "get");
3781
n.onerror = function(e) {
3782
_fail(id, e + ': ' + url);
3787
_insertInDoc = function(node, id, win) {
3789
// Add it to the head or insert it before 'insertBefore'.
3790
// Work around IE bug if there is a base tag.
3793
insertBefore = q.insertBefore || doc.getElementsByTagName('base')[0],
3797
sibling = _getNodeRef(insertBefore, id);
3799
Y.log('inserting before: ' + insertBefore, 'info', 'get');
3800
sibling.parentNode.insertBefore(node, sibling);
3803
// 3.3.0 assumed head is always around.
3804
doc.getElementsByTagName('head')[0].appendChild(node);
3809
* Loads the next item for a given request
3811
* @param {string} id the id of the request.
3812
* @return {string} the result.
3815
_next = function(id) {
3817
// Assigning out here for readability
3820
attrs = q.attributes,
3822
timeout = q.timeout,
3826
if (q.url.length > 0) {
3828
url = q.url.shift();
3830
Y.log('attempting to load ' + url, 'info', 'get');
3832
// !q.timer ensures that this only happens once for async
3833
if (timeout && !q.timer) {
3834
q.timer = setTimeout(function() {
3839
if (type === SCRIPT) {
3840
node = _scriptNode(url, win, attrs);
3842
node = _linkNode(url, win, attrs);
3845
// add the node to the queue so we can return it in the callback
3848
_trackLoad(type, node, id, url);
3849
_insertInDoc(node, id, win);
3851
if (!ONLOAD_SUPPORTED[type]) {
3856
// For sync, the _next call is chained in _loaded
3863
* Removes processed queues and corresponding nodes
3864
* @method _autoPurge
3867
_autoPurge = function() {
3876
if (queues.hasOwnProperty(i)) {
3878
if (q.autopurge && q.finished) {
3889
* Saves the state for the request and begins loading
3890
* the requested urls
3892
* @param {string} type the type of node to insert.
3893
* @param {string} url the url to load.
3894
* @param {object} opts the hash of options for this request.
3895
* @return {object} transaction object.
3898
_queue = function(type, url, opts) {
3902
var id = 'q' + (qidx++),
3903
thresh = opts.purgethreshold || Y.Get.PURGE_THRESH,
3906
if (qidx % thresh === 0) {
3910
// Merge to protect opts (grandfathered in).
3911
q = queues[id] = Y.merge(opts);
3913
// Avoid mix, merge overhead. Known set of props.
3920
q.win = q.win || Y.config.win;
3921
q.context = q.context || q;
3922
q.autopurge = (AUTOPURGE in q) ? q.autopurge : (type === SCRIPT) ? true : false;
3923
q.attributes = q.attributes || {};
3924
q.attributes.charset = opts.charset || q.attributes.charset || UTF8;
3926
if (ASYNC in q && type === SCRIPT) {
3927
q.attributes.async = q.async;
3930
q.url = (L.isString(q.url)) ? [q.url] : q.url;
3932
// TODO: Do we really need to account for this developer error?
3933
// If the url is undefined, this is probably a trailing comma problem in IE.
3936
Y.log('skipping empty url');
3939
q.remaining = q.url.length;
3952
* The number of request required before an automatic purge.
3953
* Can be configured via the 'purgethreshold' config
3954
* @property PURGE_THRESH
3963
* Abort a transaction
3966
* @param {string|object} o Either the tId or the object returned from
3967
* script() or css().
3969
abort : function(o) {
3970
var id = (L.isString(o)) ? o : o.tId,
3974
Y.log('Aborting ' + id, 'info', 'get');
3980
* Fetches and inserts one or more script nodes into the head
3981
* of the current document or the document in a specified window.
3985
* @param {string|string[]} url the url or urls to the script(s).
3986
* @param {object} opts Options:
3988
* <dt>onSuccess</dt>
3990
* callback to execute when the script(s) are finished loading
3991
* The callback receives an object back with the following
3995
* <dd>the window the script(s) were inserted into</dd>
3997
* <dd>the data object passed in when the request was made</dd>
3999
* <dd>An array containing references to the nodes that were
4002
* <dd>A function that, when executed, will remove the nodes
4003
* that were inserted</dd>
4007
* <dt>onTimeout</dt>
4009
* callback to execute when a timeout occurs.
4010
* The callback receives an object back with the following
4014
* <dd>the window the script(s) were inserted into</dd>
4016
* <dd>the data object passed in when the request was made</dd>
4018
* <dd>An array containing references to the nodes that were
4021
* <dd>A function that, when executed, will remove the nodes
4022
* that were inserted</dd>
4027
* <dd>a function that executes when the transaction finishes,
4028
* regardless of the exit path</dd>
4029
* <dt>onFailure</dt>
4031
* callback to execute when the script load operation fails
4032
* The callback receives an object back with the following
4036
* <dd>the window the script(s) were inserted into</dd>
4038
* <dd>the data object passed in when the request was made</dd>
4040
* <dd>An array containing references to the nodes that were
4041
* inserted successfully</dd>
4043
* <dd>A function that, when executed, will remove any nodes
4044
* that were inserted</dd>
4048
* <dt>onProgress</dt>
4049
* <dd>callback to execute when each individual file is done loading
4050
* (useful when passing in an array of js files). Receives the same
4051
* payload as onSuccess, with the addition of a <code>url</code>
4052
* property, which identifies the file which was loaded.</dd>
4055
* <p>When passing in an array of JS files, setting this flag to true
4056
* will insert them into the document in parallel, as opposed to the
4057
* default behavior, which is to chain load them serially. It will also
4058
* set the async attribute on the script node to true.</p>
4059
* <p>Setting async:true
4060
* will lead to optimal file download performance allowing the browser to
4061
* download multiple scripts in parallel, and execute them as soon as they
4062
* are available.</p>
4063
* <p>Note that async:true does not guarantee execution order of the
4064
* scripts being downloaded. They are executed in whichever order they
4068
* <dd>the execution context for the callbacks</dd>
4070
* <dd>a window other than the one the utility occupies</dd>
4071
* <dt>autopurge</dt>
4073
* setting to true will let the utilities cleanup routine purge
4074
* the script once loaded
4076
* <dt>purgethreshold</dt>
4078
* The number of transaction before autopurge should be initiated
4082
* data that is supplied to the callback when the script(s) are
4085
* <dt>insertBefore</dt>
4086
* <dd>node or node id that will become the new node's nextSibling.
4087
* If this is not specified, nodes will be inserted before a base
4088
* tag should it exist. Otherwise, the nodes will be appended to the
4089
* end of the document head.</dd>
4092
* <dd>Node charset, default utf-8 (deprecated, use the attributes
4094
* <dt>attributes</dt>
4095
* <dd>An object literal containing additional attributes to add to
4096
* the link tags</dd>
4098
* <dd>Number of milliseconds to wait before aborting and firing
4099
* the timeout event</dd>
4101
* Y.Get.script(
4102
* ["http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js",
4103
* "http://yui.yahooapis.com/2.5.2/build/event/event-min.js"],
4105
* onSuccess: function(o) {
4106
* this.log("won't cause error because Y is the context");
4107
* Y.log(o.data); // foo
4108
* Y.log(o.nodes.length === 2) // true
4109
* // o.purge(); // optionally remove the script nodes
4110
* // immediately
4112
* onFailure: function(o) {
4113
* Y.log("transaction failed");
4115
* onTimeout: function(o) {
4116
* Y.log("transaction timed out");
4118
* data: "foo",
4119
* timeout: 10000, // 10 second timeout
4120
* context: Y, // make the YUI instance
4121
* // win: otherframe // target another window/frame
4122
* autopurge: true // allow the utility to choose when to
4123
* // remove the nodes
4124
* purgetheshold: 1 // purge previous transaction before
4125
* // next transaction
4128
* @return {tId: string} an object containing info about the
4131
script: function(url, opts) {
4132
return _queue(SCRIPT, url, opts);
4136
* Fetches and inserts one or more css link nodes into the
4137
* head of the current document or the document in a specified
4141
* @param {string} url the url or urls to the css file(s).
4142
* @param {object} opts Options:
4144
* <dt>onSuccess</dt>
4146
* callback to execute when the css file(s) are finished loading
4147
* The callback receives an object back with the following
4150
* <dd>the window the link nodes(s) were inserted into</dd>
4152
* <dd>the data object passed in when the request was made</dd>
4154
* <dd>An array containing references to the nodes that were
4157
* <dd>A function that, when executed, will remove the nodes
4158
* that were inserted</dd>
4162
* <dt>onProgress</dt>
4163
* <dd>callback to execute when each individual file is done loading (useful when passing in an array of css files). Receives the same
4164
* payload as onSuccess, with the addition of a <code>url</code> property, which identifies the file which was loaded. Currently only useful for non Webkit/Gecko browsers,
4165
* where onload for css is detected accurately.</dd>
4167
* <dd>When passing in an array of css files, setting this flag to true will insert them
4168
* into the document in parallel, as oppposed to the default behavior, which is to chain load them (where possible).
4169
* This flag is more useful for scripts currently, since for css Get only chains if not Webkit/Gecko.</dd>
4171
* <dd>the execution context for the callbacks</dd>
4173
* <dd>a window other than the one the utility occupies</dd>
4176
* data that is supplied to the callbacks when the nodes(s) are
4179
* <dt>insertBefore</dt>
4180
* <dd>node or node id that will become the new node's nextSibling</dd>
4182
* <dd>Node charset, default utf-8 (deprecated, use the attributes
4184
* <dt>attributes</dt>
4185
* <dd>An object literal containing additional attributes to add to
4186
* the link tags</dd>
4189
* Y.Get.css("http://localhost/css/menu.css");
4193
* ["http://localhost/css/menu.css",
4194
* "http://localhost/css/logger.css"], {
4195
* insertBefore: 'custom-styles' // nodes will be inserted
4196
* // before the specified node
4199
* @return {tId: string} an object containing info about the
4202
css: function(url, opts) {
4203
return _queue('css', url, opts);
4208
}, '3.4.1' ,{requires:['yui-base']});
4209
YUI.add('features', function(Y) {
4211
var feature_tests = {};
4213
Y.mix(Y.namespace('Features'), {
4215
tests: feature_tests,
4217
add: function(cat, name, o) {
4218
feature_tests[cat] = feature_tests[cat] || {};
4219
feature_tests[cat][name] = o;
4222
all: function(cat, args) {
4223
var cat_o = feature_tests[cat],
4227
Y.Object.each(cat_o, function(v, k) {
4228
result.push(k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0));
4232
return (result.length) ? result.join(';') : '';
4235
test: function(cat, name, args) {
4237
var result, ua, test,
4238
cat_o = feature_tests[cat],
4239
feature = cat_o && cat_o[name];
4242
Y.log('Feature test ' + cat + ', ' + name + ' not found');
4245
result = feature.result;
4247
if (Y.Lang.isUndefined(result)) {
4251
result = (Y.UA[ua]);
4254
test = feature.test;
4255
if (test && ((!ua) || result)) {
4256
result = test.apply(Y, args);
4259
feature.result = result;
4267
// Y.Features.add("load", "1", {});
4268
// Y.Features.test("load", "1");
4269
// caps=1:1;2:0;3:1;
4271
/* This file is auto-generated by src/loader/scripts/meta_join.py */
4272
var add = Y.Features.add;
4275
"name": "graphics-svg",
4276
"test": function(Y) {
4277
var DOCUMENT = Y.config.doc;
4278
return (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
4280
"trigger": "graphics"
4284
"name": "event-base-ie",
4285
"test": function(Y) {
4286
var imp = Y.config.doc && Y.config.doc.implementation;
4287
return (imp && (!imp.hasFeature('Events', '2.0')));
4289
"trigger": "node-base"
4293
"name": "graphics-vml",
4294
"test": function(Y) {
4295
var DOCUMENT = Y.config.doc,
4296
canvas = DOCUMENT && DOCUMENT.createElement("canvas");
4297
return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
4299
"trigger": "graphics"
4303
"name": "dom-style-ie",
4304
"test": function (Y) {
4306
var testFeature = Y.Features.test,
4307
addFeature = Y.Features.add,
4308
WINDOW = Y.config.win,
4309
DOCUMENT = Y.config.doc,
4310
DOCUMENT_ELEMENT = 'documentElement',
4313
addFeature('style', 'computedStyle', {
4315
return WINDOW && 'getComputedStyle' in WINDOW;
4319
addFeature('style', 'opacity', {
4321
return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
4325
ret = (!testFeature('style', 'opacity') &&
4326
!testFeature('style', 'computedStyle'));
4330
"trigger": "dom-style"
4332
// transition-test.js
4334
"name": "transition-timer",
4335
"test": function (Y) {
4336
var DOCUMENT = Y.config.doc,
4337
node = (DOCUMENT) ? DOCUMENT.documentElement: null,
4340
if (node && node.style) {
4341
ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style);
4346
"trigger": "transition"
4350
"name": "widget-base-ie",
4351
"trigger": "widget-base",
4354
// autocomplete-list-keys-sniff.js
4356
"name": "autocomplete-list-keys",
4357
"test": function (Y) {
4358
// Only add keyboard support to autocomplete-list if this doesn't appear to
4359
// be an iOS or Android-based mobile device.
4361
// There's currently no feasible way to actually detect whether a device has
4362
// a hardware keyboard, so this sniff will have to do. It can easily be
4363
// overridden by manually loading the autocomplete-list-keys module.
4365
// Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
4366
// doesn't fire the keyboard events used by AutoCompleteList, so there's
4367
// no point loading the -keys module even when a bluetooth keyboard may be
4369
return !(Y.UA.ios || Y.UA.android);
4371
"trigger": "autocomplete-list"
4373
// graphics-canvas.js
4375
"name": "graphics-canvas-default",
4376
"test": function(Y) {
4377
var DOCUMENT = Y.config.doc,
4378
canvas = DOCUMENT && DOCUMENT.createElement("canvas");
4379
return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (canvas && canvas.getContext && canvas.getContext("2d")));
4381
"trigger": "graphics"
4383
// dd-gestures-test.js
4385
"name": "dd-gestures",
4386
"test": function(Y) {
4387
return (Y.config.win && ('ontouchstart' in Y.config.win && !Y.UA.chrome));
4389
"trigger": "dd-drag"
4393
"name": "selector-css2",
4394
"test": function (Y) {
4395
var DOCUMENT = Y.config.doc,
4396
ret = DOCUMENT && !('querySelectorAll' in DOCUMENT);
4400
"trigger": "selector"
4402
// history-hash-ie-test.js
4404
"name": "history-hash-ie",
4405
"test": function (Y) {
4406
var docMode = Y.config.doc && Y.config.doc.documentMode;
4408
return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
4409
!docMode || docMode < 8);
4411
"trigger": "history-hash"
4415
}, '3.4.1' ,{requires:['yui-base']});
4416
YUI.add('intl-base', function(Y) {
4419
* The Intl utility provides a central location for managing sets of
4420
* localized resources (strings and formatting patterns).
4427
var SPLIT_REGEX = /[, ]/;
4429
Y.mix(Y.namespace('Intl'), {
4432
* Returns the language among those available that
4433
* best matches the preferred language list, using the Lookup
4434
* algorithm of BCP 47.
4435
* If none of the available languages meets the user's preferences,
4436
* then "" is returned.
4437
* Extended language ranges are not supported.
4439
* @method lookupBestLang
4440
* @param {String[] | String} preferredLanguages The list of preferred
4441
* languages in descending preference order, represented as BCP 47
4442
* language tags. A string array or a comma-separated list.
4443
* @param {String[]} availableLanguages The list of languages
4444
* that the application supports, represented as BCP 47 language
4447
* @return {String} The available language that best matches the
4448
* preferred language list, or "".
4451
lookupBestLang: function(preferredLanguages, availableLanguages) {
4453
var i, language, result, index;
4455
// check whether the list of available languages contains language;
4457
function scan(language) {
4459
for (i = 0; i < availableLanguages.length; i += 1) {
4460
if (language.toLowerCase() ===
4461
availableLanguages[i].toLowerCase()) {
4462
return availableLanguages[i];
4467
if (Y.Lang.isString(preferredLanguages)) {
4468
preferredLanguages = preferredLanguages.split(SPLIT_REGEX);
4471
for (i = 0; i < preferredLanguages.length; i += 1) {
4472
language = preferredLanguages[i];
4473
if (!language || language === '*') {
4476
// check the fallback sequence for one language
4477
while (language.length > 0) {
4478
result = scan(language);
4482
index = language.lastIndexOf('-');
4484
language = language.substring(0, index);
4485
// one-character subtags get cut along with the
4487
if (index >= 2 && language.charAt(index - 2) === '-') {
4488
language = language.substring(0, index - 2);
4491
// nothing available for this language
4503
}, '3.4.1' ,{requires:['yui-base']});
4504
YUI.add('yui-log', function(Y) {
4507
* Provides console log capability and exposes a custom event for
4508
* console implementations. This module is a `core` YUI module, <a href="../classes/YUI.html#method_log">it's documentation is located under the YUI class</a>.
4511
* @submodule yui-log
4515
LOGEVENT = 'yui:log',
4516
UNDEFINED = 'undefined',
4517
LEVELS = { debug: 1,
4523
* If the 'debug' config is true, a 'yui:log' event will be
4524
* dispatched, which the Console widget and anything else
4525
* can consume. If the 'useBrowserConsole' config is true, it will
4526
* write to the browser console if available. YUI-specific log
4527
* messages will only be present in the -debug versions of the
4528
* JS files. The build system is supposed to remove log statements
4529
* from the raw and minified versions of the files.
4533
* @param {String} msg The message to log.
4534
* @param {String} cat The log category for the message. Default
4535
* categories are "info", "warn", "error", time".
4536
* Custom categories can be used as well. (opt).
4537
* @param {String} src The source of the the message (opt).
4538
* @param {boolean} silent If true, the log event won't fire.
4539
* @return {YUI} YUI instance.
4541
INSTANCE.log = function(msg, cat, src, silent) {
4542
var bail, excl, incl, m, f,
4545
publisher = (Y.fire) ? Y : YUI.Env.globalEvents;
4546
// suppress log message if the config is off or the event stack
4547
// or the event call stack contains a consumer of the yui:log event
4549
// apply source filters
4551
excl = c.logExclude;
4552
incl = c.logInclude;
4553
if (incl && !(src in incl)) {
4555
} else if (incl && (src in incl)) {
4557
} else if (excl && (src in excl)) {
4562
if (c.useBrowserConsole) {
4563
m = (src) ? src + ': ' + msg : msg;
4564
if (Y.Lang.isFunction(c.logFn)) {
4565
c.logFn.call(Y, msg, cat, src);
4566
} else if (typeof console != UNDEFINED && console.log) {
4567
f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log';
4569
} else if (typeof opera != UNDEFINED) {
4574
if (publisher && !silent) {
4576
if (publisher == Y && (!publisher.getEvent(LOGEVENT))) {
4577
publisher.publish(LOGEVENT, {
4582
publisher.fire(LOGEVENT, {
4595
* Write a system message. This message will be preserved in the
4596
* minified and raw versions of the YUI files, unlike log statements.
4599
* @param {String} msg The message to log.
4600
* @param {String} cat The log category for the message. Default
4601
* categories are "info", "warn", "error", time".
4602
* Custom categories can be used as well. (opt).
4603
* @param {String} src The source of the the message (opt).
4604
* @param {boolean} silent If true, the log event won't fire.
4605
* @return {YUI} YUI instance.
4607
INSTANCE.message = function() {
4608
return INSTANCE.log.apply(INSTANCE, arguments);
4612
}, '3.4.1' ,{requires:['yui-base']});
4613
YUI.add('yui-later', function(Y) {
4616
* Provides a setTimeout/setInterval wrapper. This module is a `core` YUI module, <a href="../classes/YUI.html#method_later">it's documentation is located under the YUI class</a>.
4619
* @submodule yui-later
4625
* Executes the supplied function in the context of the supplied
4626
* object 'when' milliseconds later. Executes the function a
4627
* single time unless periodic is set to true.
4630
* @param when {int} the number of milliseconds to wait until the fn
4632
* @param o the context object.
4633
* @param fn {Function|String} the function to execute or the name of
4634
* the method in the 'o' object to execute.
4635
* @param data [Array] data that is provided to the function. This
4636
* accepts either a single item or an array. If an array is provided,
4637
* the function is executed with one parameter for each array item.
4638
* If you need to pass a single array parameter, it needs to be wrapped
4639
* in an array [myarray].
4641
* Note: native methods in IE may not have the call and apply methods.
4642
* In this case, it will work, but you are limited to four arguments.
4644
* @param periodic {boolean} if true, executes continuously at supplied
4645
* interval until canceled.
4646
* @return {object} a timer object. Call the cancel() method on this
4647
* object to stop the timer.
4649
Y.later = function(when, o, fn, data, periodic) {
4651
data = (!Y.Lang.isUndefined(data)) ? Y.Array(data) : data;
4653
var cancelled = false,
4654
method = (o && Y.Lang.isString(fn)) ? o[fn] : fn,
4655
wrapper = function() {
4656
// IE 8- may execute a setInterval callback one last time
4657
// after clearInterval was called, so in order to preserve
4658
// the cancel() === no more runny-run, we have to jump through
4661
if (!method.apply) {
4662
method(data[0], data[1], data[2], data[3]);
4664
method.apply(o, data || NO_ARGS);
4668
id = (periodic) ? setInterval(wrapper, when) : setTimeout(wrapper, when);
4673
cancel: function() {
4675
if (this.interval) {
4684
Y.Lang.later = Y.later;
4688
}, '3.4.1' ,{requires:['yui-base']});
4691
YUI.add('yui', function(Y){}, '3.4.1' ,{use:['yui-base','get','features','intl-base','yui-log','yui-later']});
4693
YUI.add('oop', function(Y) {
4696
Adds object inheritance and manipulation utilities to the YUI instance. This
4697
module is required by most YUI components.
4704
OP = Object.prototype,
4705
CLONE_MARKER = '_~yuim~_',
4707
hasOwn = OP.hasOwnProperty,
4708
toString = OP.toString;
4710
function dispatch(o, f, c, proto, action) {
4711
if (o && o[action] && o !== Y) {
4712
return o[action].call(o, f, c);
4714
switch (A.test(o)) {
4716
return A[action](o, f, c);
4718
return A[action](Y.Array(o, 0, true), f, c);
4720
return Y.Object[action](o, f, c, proto);
4726
Augments the _receiver_ with prototype properties from the _supplier_. The
4727
receiver may be a constructor function or an object. The supplier must be a
4728
constructor function.
4730
If the _receiver_ is an object, then the _supplier_ constructor will be called
4731
immediately after _receiver_ is augmented, with _receiver_ as the `this` object.
4733
If the _receiver_ is a constructor function, then all prototype methods of
4734
_supplier_ that are copied to _receiver_ will be sequestered, and the
4735
_supplier_ constructor will not be called immediately. The first time any
4736
sequestered method is called on the _receiver_'s prototype, all sequestered
4737
methods will be immediately copied to the _receiver_'s prototype, the
4738
_supplier_'s constructor will be executed, and finally the newly unsequestered
4739
method that was called will be executed.
4741
This sequestering logic sounds like a bunch of complicated voodoo, but it makes
4742
it cheap to perform frequent augmentation by ensuring that suppliers'
4743
constructors are only called if a supplied method is actually used. If none of
4744
the supplied methods is ever used, then there's no need to take the performance
4745
hit of calling the _supplier_'s constructor.
4748
@param {Function|Object} receiver Object or function to be augmented.
4749
@param {Function} supplier Function that supplies the prototype properties with
4750
which to augment the _receiver_.
4751
@param {Boolean} [overwrite=false] If `true`, properties already on the receiver
4752
will be overwritten if found on the supplier's prototype.
4753
@param {String[]} [whitelist] An array of property names. If specified,
4754
only the whitelisted prototype properties will be applied to the receiver, and
4755
all others will be ignored.
4756
@param {Array|any} [args] Argument or array of arguments to pass to the
4757
supplier's constructor when initializing.
4758
@return {Function} Augmented object.
4761
Y.augment = function (receiver, supplier, overwrite, whitelist, args) {
4762
var rProto = receiver.prototype,
4763
sequester = rProto && supplier,
4764
sProto = supplier.prototype,
4765
to = rProto || receiver,
4773
args = args ? Y.Array(args) : [];
4780
copy = function (value, key) {
4781
if (overwrite || !(key in rProto)) {
4782
if (toString.call(value) === '[object Function]') {
4783
sequestered[key] = value;
4785
newPrototype[key] = replacements[key] = function () {
4786
return unsequester(this, value, arguments);
4789
newPrototype[key] = value;
4794
unsequester = function (instance, fn, fnArgs) {
4795
// Unsequester all sequestered functions.
4796
for (var key in sequestered) {
4797
if (hasOwn.call(sequestered, key)
4798
&& instance[key] === replacements[key]) {
4800
instance[key] = sequestered[key];
4804
// Execute the supplier constructor.
4805
supplier.apply(instance, args);
4807
// Finally, execute the original sequestered function.
4808
return fn.apply(instance, fnArgs);
4812
Y.Array.each(whitelist, function (name) {
4813
if (name in sProto) {
4814
copy(sProto[name], name);
4818
Y.Object.each(sProto, copy, null, true);
4822
Y.mix(to, newPrototype || sProto, overwrite, whitelist);
4825
supplier.apply(to, args);
4832
* Applies object properties from the supplier to the receiver. If
4833
* the target has the property, and the property is an object, the target
4834
* object will be augmented with the supplier's value. If the property
4835
* is an array, the suppliers value will be appended to the target.
4837
* @param {function} r the object to receive the augmentation.
4838
* @param {function} s the object that supplies the properties to augment.
4839
* @param {boolean} ov if true, properties already on the receiver
4840
* will be overwritten if found on the supplier.
4841
* @param {string[]} wl a whitelist. If supplied, only properties in
4842
* this list will be applied to the receiver.
4843
* @return {object} the extended object.
4845
Y.aggregate = function(r, s, ov, wl) {
4846
return Y.mix(r, s, ov, wl, 0, true);
4850
* Utility to set up the prototype, constructor and superclass properties to
4851
* support an inheritance strategy that can chain constructors and methods.
4852
* Static members will not be inherited.
4855
* @param {function} r the object to modify.
4856
* @param {function} s the object to inherit.
4857
* @param {object} px prototype properties to add/override.
4858
* @param {object} sx static properties to add/override.
4859
* @return {object} the extended object.
4861
Y.extend = function(r, s, px, sx) {
4863
Y.error('extend failed, verify dependencies');
4866
var sp = s.prototype, rp = Y.Object(sp);
4872
// assign constructor property
4873
if (s != Object && sp.constructor == OP.constructor) {
4877
// add prototype overrides
4879
Y.mix(rp, px, true);
4882
// add object overrides
4891
* Executes the supplied function for each item in
4892
* a collection. Supports arrays, objects, and
4895
* @param {object} o the object to iterate.
4896
* @param {function} f the function to execute. This function
4897
* receives the value, key, and object as parameters.
4898
* @param {object} c the execution context for the function.
4899
* @param {boolean} proto if true, prototype properties are
4900
* iterated on objects.
4901
* @return {YUI} the YUI instance.
4903
Y.each = function(o, f, c, proto) {
4904
return dispatch(o, f, c, proto, 'each');
4908
* Executes the supplied function for each item in
4909
* a collection. The operation stops if the function
4910
* returns true. Supports arrays, objects, and
4913
* @param {object} o the object to iterate.
4914
* @param {function} f the function to execute. This function
4915
* receives the value, key, and object as parameters.
4916
* @param {object} c the execution context for the function.
4917
* @param {boolean} proto if true, prototype properties are
4918
* iterated on objects.
4919
* @return {boolean} true if the function ever returns true,
4922
Y.some = function(o, f, c, proto) {
4923
return dispatch(o, f, c, proto, 'some');
4927
* Deep object/array copy. Function clones are actually
4928
* wrappers around the original function.
4929
* Array-like objects are treated as arrays.
4930
* Primitives are returned untouched. Optionally, a
4931
* function can be provided to handle other data types,
4932
* filter keys, validate values, etc.
4935
* @param {object} o what to clone.
4936
* @param {boolean} safe if true, objects will not have prototype
4937
* items from the source. If false, they will. In this case, the
4938
* original is initially protected, but the clone is not completely
4939
* immune from changes to the source object prototype. Also, cloned
4940
* prototype items that are deleted from the clone will result
4941
* in the value of the source prototype being exposed. If operating
4942
* on a non-safe clone, items should be nulled out rather than deleted.
4943
* @param {function} f optional function to apply to each item in a
4944
* collection; it will be executed prior to applying the value to
4945
* the new object. Return false to prevent the copy.
4946
* @param {object} c optional execution context for f.
4947
* @param {object} owner Owner object passed when clone is iterating
4948
* an object. Used to set up context for cloned functions.
4949
* @param {object} cloned hash of previously cloned objects to avoid
4951
* @return {Array|Object} the cloned object.
4953
Y.clone = function(o, safe, f, c, owner, cloned) {
4955
if (!L.isObject(o)) {
4959
// @todo cloning YUI instances doesn't currently work
4960
if (Y.instanceOf(o, YUI)) {
4964
var o2, marked = cloned || {}, stamp,
4967
switch (L.type(o)) {
4971
// if we do this we need to set the flags too
4972
// return new RegExp(o.source);
4975
// o2 = Y.bind(o, owner);
4983
// #2528250 only one clone of a given object should be created.
4984
if (o[CLONE_MARKER]) {
4985
return marked[o[CLONE_MARKER]];
4990
o2 = (safe) ? {} : Y.Object(o);
4992
o[CLONE_MARKER] = stamp;
4996
// #2528250 don't try to clone element properties
4997
if (!o.addEventListener && !o.attachEvent) {
4998
yeach(o, function(v, k) {
4999
if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
5000
if (k !== CLONE_MARKER) {
5001
if (k == 'prototype') {
5002
// skip the prototype
5003
// } else if (o[k] === o) {
5007
Y.clone(v, safe, f, c, owner || o, marked);
5015
Y.Object.each(marked, function(v, k) {
5016
if (v[CLONE_MARKER]) {
5018
delete v[CLONE_MARKER];
5020
v[CLONE_MARKER] = null;
5032
* Returns a function that will execute the supplied function in the
5033
* supplied object's context, optionally adding any additional
5034
* supplied parameters to the beginning of the arguments collection the
5035
* supplied to the function.
5038
* @param {Function|String} f the function to bind, or a function name
5039
* to execute on the context object.
5040
* @param {object} c the execution context.
5041
* @param {any} args* 0..n arguments to include before the arguments the
5042
* function is executed with.
5043
* @return {function} the wrapped function.
5045
Y.bind = function(f, c) {
5046
var xargs = arguments.length > 2 ?
5047
Y.Array(arguments, 2, true) : null;
5049
var fn = L.isString(f) ? c[f] : f,
5051
xargs.concat(Y.Array(arguments, 0, true)) : arguments;
5052
return fn.apply(c || fn, args);
5057
* Returns a function that will execute the supplied function in the
5058
* supplied object's context, optionally adding any additional
5059
* supplied parameters to the end of the arguments the function
5063
* @param {Function|String} f the function to bind, or a function name
5064
* to execute on the context object.
5065
* @param {object} c the execution context.
5066
* @param {any} args* 0..n arguments to append to the end of
5067
* arguments collection supplied to the function.
5068
* @return {function} the wrapped function.
5070
Y.rbind = function(f, c) {
5071
var xargs = arguments.length > 2 ? Y.Array(arguments, 2, true) : null;
5073
var fn = L.isString(f) ? c[f] : f,
5075
Y.Array(arguments, 0, true).concat(xargs) : arguments;
5076
return fn.apply(c || fn, args);
5081
}, '3.4.1' ,{requires:['yui-base']});
5082
YUI.add('features', function(Y) {
5084
var feature_tests = {};
5086
Y.mix(Y.namespace('Features'), {
5088
tests: feature_tests,
5090
add: function(cat, name, o) {
5091
feature_tests[cat] = feature_tests[cat] || {};
5092
feature_tests[cat][name] = o;
5095
all: function(cat, args) {
5096
var cat_o = feature_tests[cat],
5100
Y.Object.each(cat_o, function(v, k) {
5101
result.push(k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0));
5105
return (result.length) ? result.join(';') : '';
5108
test: function(cat, name, args) {
5110
var result, ua, test,
5111
cat_o = feature_tests[cat],
5112
feature = cat_o && cat_o[name];
5115
Y.log('Feature test ' + cat + ', ' + name + ' not found');
5118
result = feature.result;
5120
if (Y.Lang.isUndefined(result)) {
5124
result = (Y.UA[ua]);
5127
test = feature.test;
5128
if (test && ((!ua) || result)) {
5129
result = test.apply(Y, args);
5132
feature.result = result;
5140
// Y.Features.add("load", "1", {});
5141
// Y.Features.test("load", "1");
5142
// caps=1:1;2:0;3:1;
5144
/* This file is auto-generated by src/loader/scripts/meta_join.py */
5145
var add = Y.Features.add;
5148
"name": "graphics-svg",
5149
"test": function(Y) {
5150
var DOCUMENT = Y.config.doc;
5151
return (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
5153
"trigger": "graphics"
5157
"name": "event-base-ie",
5158
"test": function(Y) {
5159
var imp = Y.config.doc && Y.config.doc.implementation;
5160
return (imp && (!imp.hasFeature('Events', '2.0')));
5162
"trigger": "node-base"
5166
"name": "graphics-vml",
5167
"test": function(Y) {
5168
var DOCUMENT = Y.config.doc,
5169
canvas = DOCUMENT && DOCUMENT.createElement("canvas");
5170
return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
5172
"trigger": "graphics"
5176
"name": "dom-style-ie",
5177
"test": function (Y) {
5179
var testFeature = Y.Features.test,
5180
addFeature = Y.Features.add,
5181
WINDOW = Y.config.win,
5182
DOCUMENT = Y.config.doc,
5183
DOCUMENT_ELEMENT = 'documentElement',
5186
addFeature('style', 'computedStyle', {
5188
return WINDOW && 'getComputedStyle' in WINDOW;
5192
addFeature('style', 'opacity', {
5194
return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
5198
ret = (!testFeature('style', 'opacity') &&
5199
!testFeature('style', 'computedStyle'));
5203
"trigger": "dom-style"
5205
// transition-test.js
5207
"name": "transition-timer",
5208
"test": function (Y) {
5209
var DOCUMENT = Y.config.doc,
5210
node = (DOCUMENT) ? DOCUMENT.documentElement: null,
5213
if (node && node.style) {
5214
ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style);
5219
"trigger": "transition"
5223
"name": "widget-base-ie",
5224
"trigger": "widget-base",
5227
// autocomplete-list-keys-sniff.js
5229
"name": "autocomplete-list-keys",
5230
"test": function (Y) {
5231
// Only add keyboard support to autocomplete-list if this doesn't appear to
5232
// be an iOS or Android-based mobile device.
5234
// There's currently no feasible way to actually detect whether a device has
5235
// a hardware keyboard, so this sniff will have to do. It can easily be
5236
// overridden by manually loading the autocomplete-list-keys module.
5238
// Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
5239
// doesn't fire the keyboard events used by AutoCompleteList, so there's
5240
// no point loading the -keys module even when a bluetooth keyboard may be
5242
return !(Y.UA.ios || Y.UA.android);
5244
"trigger": "autocomplete-list"
5246
// graphics-canvas.js
5248
"name": "graphics-canvas-default",
5249
"test": function(Y) {
5250
var DOCUMENT = Y.config.doc,
5251
canvas = DOCUMENT && DOCUMENT.createElement("canvas");
5252
return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (canvas && canvas.getContext && canvas.getContext("2d")));
5254
"trigger": "graphics"
5256
// dd-gestures-test.js
5258
"name": "dd-gestures",
5259
"test": function(Y) {
5260
return (Y.config.win && ('ontouchstart' in Y.config.win && !Y.UA.chrome));
5262
"trigger": "dd-drag"
5266
"name": "selector-css2",
5267
"test": function (Y) {
5268
var DOCUMENT = Y.config.doc,
5269
ret = DOCUMENT && !('querySelectorAll' in DOCUMENT);
5273
"trigger": "selector"
5275
// history-hash-ie-test.js
5277
"name": "history-hash-ie",
5278
"test": function (Y) {
5279
var docMode = Y.config.doc && Y.config.doc.documentMode;
5281
return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
5282
!docMode || docMode < 8);
5284
"trigger": "history-hash"
5288
}, '3.4.1' ,{requires:['yui-base']});
5289
YUI.add('dom-core', function(Y) {
5291
var NODE_TYPE = 'nodeType',
5292
OWNER_DOCUMENT = 'ownerDocument',
5293
DOCUMENT_ELEMENT = 'documentElement',
5294
DEFAULT_VIEW = 'defaultView',
5295
PARENT_WINDOW = 'parentWindow',
5296
TAG_NAME = 'tagName',
5297
PARENT_NODE = 'parentNode',
5298
PREVIOUS_SIBLING = 'previousSibling',
5299
NEXT_SIBLING = 'nextSibling',
5300
CONTAINS = 'contains',
5301
COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
5305
* The DOM utility provides a cross-browser abtraction layer
5306
* normalizing DOM tasks, and adds extra helper functionality
5307
* for other common tasks.
5309
* @submodule dom-base
5315
* Provides DOM helper methods.
5322
* Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
5324
* @param {String} id the id attribute
5325
* @param {Object} doc optional The document to search. Defaults to current document
5326
* @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
5328
byId: function(id, doc) {
5329
// handle dupe IDs and IE name collision
5330
return Y_DOM.allById(id, doc)[0] || null;
5334
* Finds the ancestor of the element.
5336
* @param {HTMLElement} element The html element.
5337
* @param {Function} fn optional An optional boolean test to apply.
5338
* The optional function is passed the current DOM node being tested as its only argument.
5339
* If no function is given, the parentNode is returned.
5340
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
5341
* @return {HTMLElement | null} The matching DOM node or null if none found.
5343
ancestor: function(element, fn, testSelf) {
5346
ret = (!fn || fn(element)) ? element : null;
5349
return ret || Y_DOM.elementByAxis(element, PARENT_NODE, fn, null);
5353
* Finds the ancestors of the element.
5355
* @param {HTMLElement} element The html element.
5356
* @param {Function} fn optional An optional boolean test to apply.
5357
* The optional function is passed the current DOM node being tested as its only argument.
5358
* If no function is given, all ancestors are returned.
5359
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
5360
* @return {Array} An array containing all matching DOM nodes.
5362
ancestors: function(element, fn, testSelf) {
5363
var ancestor = Y_DOM.ancestor.apply(Y_DOM, arguments),
5364
ret = (ancestor) ? [ancestor] : [];
5366
while ((ancestor = Y_DOM.ancestor(ancestor, fn))) {
5368
ret.unshift(ancestor);
5376
* Searches the element by the given axis for the first matching element.
5377
* @method elementByAxis
5378
* @param {HTMLElement} element The html element.
5379
* @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
5380
* @param {Function} fn optional An optional boolean test to apply.
5381
* @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
5382
* The optional function is passed the current HTMLElement being tested as its only argument.
5383
* If no function is given, the first element is returned.
5384
* @return {HTMLElement | null} The matching element or null if none found.
5386
elementByAxis: function(element, axis, fn, all) {
5387
while (element && (element = element[axis])) { // NOTE: assignment
5388
if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
5396
* Determines whether or not one HTMLElement is or contains another HTMLElement.
5398
* @param {HTMLElement} element The containing html element.
5399
* @param {HTMLElement} needle The html element that may be contained.
5400
* @return {Boolean} Whether or not the element is or contains the needle.
5402
contains: function(element, needle) {
5405
if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
5407
} else if (element[CONTAINS]) {
5408
if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
5409
ret = element[CONTAINS](needle);
5411
ret = Y_DOM._bruteContains(element, needle);
5413
} else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
5414
if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
5423
* Determines whether or not the HTMLElement is part of the document.
5425
* @param {HTMLElement} element The containing html element.
5426
* @param {HTMLElement} doc optional The document to check.
5427
* @return {Boolean} Whether or not the element is attached to the document.
5429
inDoc: function(element, doc) {
5433
if (element && element.nodeType) {
5434
(doc) || (doc = element[OWNER_DOCUMENT]);
5436
rootNode = doc[DOCUMENT_ELEMENT];
5438
// contains only works with HTML_ELEMENT
5439
if (rootNode && rootNode.contains && element.tagName) {
5440
ret = rootNode.contains(element);
5442
ret = Y_DOM.contains(rootNode, element);
5450
allById: function(id, root) {
5451
root = root || Y.config.doc;
5457
if (root.querySelectorAll) {
5458
ret = root.querySelectorAll('[id="' + id + '"]');
5459
} else if (root.all) {
5460
nodes = root.all(id);
5463
// root.all may return HTMLElement or HTMLCollection.
5464
// some elements are also HTMLCollection (FORM, SELECT).
5465
if (nodes.nodeName) {
5466
if (nodes.id === id) { // avoid false positive on name
5468
nodes = EMPTY_ARRAY; // done, no need to filter
5469
} else { // prep for filtering
5475
// filter out matches on node.name
5476
// and element.id as reference to element with id === 'id'
5477
for (i = 0; node = nodes[i++];) {
5478
if (node.id === id ||
5479
(node.attributes && node.attributes.id &&
5480
node.attributes.id.value === id)) {
5487
ret = [Y_DOM._getDoc(root).getElementById(id)];
5494
isWindow: function(obj) {
5495
return !!(obj && obj.alert && obj.document);
5498
_removeChildNodes: function(node) {
5499
while (node.firstChild) {
5500
node.removeChild(node.firstChild);
5504
siblings: function(node, fn) {
5508
while ((sibling = sibling[PREVIOUS_SIBLING])) {
5509
if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
5510
nodes.unshift(sibling);
5515
while ((sibling = sibling[NEXT_SIBLING])) {
5516
if (sibling[TAG_NAME] && (!fn || fn(sibling))) {
5517
nodes.push(sibling);
5525
* Brute force version of contains.
5526
* Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
5527
* @method _bruteContains
5529
* @param {HTMLElement} element The containing html element.
5530
* @param {HTMLElement} needle The html element that may be contained.
5531
* @return {Boolean} Whether or not the element is or contains the needle.
5533
_bruteContains: function(element, needle) {
5535
if (element === needle) {
5538
needle = needle.parentNode;
5543
// TODO: move to Lang?
5545
* Memoizes dynamic regular expressions to boost runtime performance.
5546
* @method _getRegExp
5548
* @param {String} str The string to convert to a regular expression.
5549
* @param {String} flags optional An optinal string of flags.
5550
* @return {RegExp} An instance of RegExp
5552
_getRegExp: function(str, flags) {
5553
flags = flags || '';
5554
Y_DOM._regexCache = Y_DOM._regexCache || {};
5555
if (!Y_DOM._regexCache[str + flags]) {
5556
Y_DOM._regexCache[str + flags] = new RegExp(str, flags);
5558
return Y_DOM._regexCache[str + flags];
5561
// TODO: make getDoc/Win true privates?
5563
* returns the appropriate document.
5566
* @param {HTMLElement} element optional Target element.
5567
* @return {Object} The document for the given element or the default document.
5569
_getDoc: function(element) {
5570
var doc = Y.config.doc;
5572
doc = (element[NODE_TYPE] === 9) ? element : // element === document
5573
element[OWNER_DOCUMENT] || // element === DOM node
5574
element.document || // element === window
5575
Y.config.doc; // default
5582
* returns the appropriate window.
5585
* @param {HTMLElement} element optional Target element.
5586
* @return {Object} The window for the given element or the default window.
5588
_getWin: function(element) {
5589
var doc = Y_DOM._getDoc(element);
5590
return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
5593
_batch: function(nodes, fn, arg1, arg2, arg3, etc) {
5594
fn = (typeof fn === 'string') ? Y_DOM[fn] : fn;
5601
while ((node = nodes[i++])) {
5602
result = result = fn.call(Y_DOM, node, arg1, arg2, arg3, etc);
5603
if (typeof result !== 'undefined') {
5604
(ret) || (ret = []);
5610
return (typeof ret !== 'undefined') ? ret : nodes;
5613
wrap: function(node, html) {
5614
var parent = Y.DOM.create(html),
5615
nodes = parent.getElementsByTagName('*');
5618
parent = nodes[nodes.length - 1];
5621
if (node.parentNode) {
5622
node.parentNode.replaceChild(parent, node);
5624
parent.appendChild(node);
5627
unwrap: function(node) {
5628
var parent = node.parentNode,
5629
lastChild = parent.lastChild,
5634
grandparent = parent.parentNode;
5636
node = parent.firstChild;
5637
while (node !== lastChild) {
5638
next = node.nextSibling;
5639
grandparent.insertBefore(node, parent);
5642
grandparent.replaceChild(lastChild, parent);
5644
parent.removeChild(node);
5649
generateID: function(el) {
5665
}, '3.4.1' ,{requires:['oop','features']});
5666
YUI.add('dom-base', function(Y) {
5668
var documentElement = Y.config.doc.documentElement,
5670
TAG_NAME = 'tagName',
5671
OWNER_DOCUMENT = 'ownerDocument',
5673
addFeature = Y.Features.add,
5674
testFeature = Y.Features.test;
5678
* Returns the text content of the HTMLElement.
5680
* @param {HTMLElement} element The html element.
5681
* @return {String} The text content of the element (includes text of any descending elements).
5683
getText: (documentElement.textContent !== undefined) ?
5687
ret = element.textContent;
5690
} : function(element) {
5693
ret = element.innerText || element.nodeValue; // might be a textNode
5699
* Sets the text content of the HTMLElement.
5701
* @param {HTMLElement} element The html element.
5702
* @param {String} content The content to add.
5704
setText: (documentElement.textContent !== undefined) ?
5705
function(element, content) {
5707
element.textContent = content;
5709
} : function(element, content) {
5710
if ('innerText' in element) {
5711
element.innerText = content;
5712
} else if ('nodeValue' in element) {
5713
element.nodeValue = content;
5717
CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8
5719
'class': 'className'
5722
'className': 'class'
5726
* Provides a normalized attribute interface.
5727
* @method setAttribute
5728
* @param {HTMLElement} el The target element for the attribute.
5729
* @param {String} attr The attribute to set.
5730
* @param {String} val The value of the attribute.
5732
setAttribute: function(el, attr, val, ieAttr) {
5733
if (el && attr && el.setAttribute) {
5734
attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
5735
el.setAttribute(attr, val, ieAttr);
5737
else { Y.log('bad input to setAttribute', 'warn', 'dom'); }
5742
* Provides a normalized attribute interface.
5743
* @method getAttibute
5744
* @param {HTMLElement} el The target element for the attribute.
5745
* @param {String} attr The attribute to get.
5746
* @return {String} The current value of the attribute.
5748
getAttribute: function(el, attr, ieAttr) {
5749
ieAttr = (ieAttr !== undefined) ? ieAttr : 2;
5751
if (el && attr && el.getAttribute) {
5752
attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr;
5753
ret = el.getAttribute(attr, ieAttr);
5756
ret = ''; // per DOM spec
5759
else { Y.log('bad input to getAttribute', 'warn', 'dom'); }
5767
getValue: function(node) {
5768
var ret = '', // TODO: return null?
5771
if (node && node[TAG_NAME]) {
5772
getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
5781
// workaround for IE8 JSON stringify bug
5782
// which converts empty string values to null
5783
if (ret === EMPTY_STRING) {
5784
ret = EMPTY_STRING; // for real
5787
return (typeof ret === 'string') ? ret : '';
5790
setValue: function(node, val) {
5793
if (node && node[TAG_NAME]) {
5794
setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
5807
addFeature('value-set', 'select', {
5809
var node = Y.config.doc.createElement('select');
5810
node.innerHTML = '<option>1</option><option>2</option>';
5812
return (node.value && node.value === '2');
5816
if (!testFeature('value-set', 'select')) {
5817
Y_DOM.VALUE_SETTERS.select = function(node, val) {
5818
for (var i = 0, options = node.getElementsByTagName('option'), option;
5819
option = options[i++];) {
5820
if (Y_DOM.getValue(option) === val) {
5821
option.selected = true;
5822
//Y_DOM.setAttribute(option, 'selected', 'selected');
5829
Y.mix(Y_DOM.VALUE_GETTERS, {
5830
button: function(node) {
5831
return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
5835
Y.mix(Y_DOM.VALUE_SETTERS, {
5836
// IE: node.value changes the button text, which should be handled via innerHTML
5837
button: function(node, val) {
5838
var attr = node.attributes.value;
5840
attr = node[OWNER_DOCUMENT].createAttribute('value');
5841
node.setAttributeNode(attr);
5849
Y.mix(Y_DOM.VALUE_GETTERS, {
5850
option: function(node) {
5851
var attrs = node.attributes;
5852
return (attrs.value && attrs.value.specified) ? node.value : node.text;
5855
select: function(node) {
5856
var val = node.value,
5857
options = node.options;
5859
if (options && options.length) {
5860
// TODO: implement multipe select
5861
if (node.multiple) {
5862
Y.log('multiple select normalization not implemented', 'warn', 'DOM');
5864
val = Y_DOM.getValue(options[node.selectedIndex]);
5871
var addClass, hasClass, removeClass;
5875
* Determines whether a DOM element has the given className.
5878
* @param {HTMLElement} element The DOM element.
5879
* @param {String} className the class name to search for
5880
* @return {Boolean} Whether or not the element has the given class.
5882
hasClass: function(node, className) {
5883
var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
5884
return re.test(node.className);
5888
* Adds a class name to a given DOM element.
5891
* @param {HTMLElement} element The DOM element.
5892
* @param {String} className the class name to add to the class attribute
5894
addClass: function(node, className) {
5895
if (!Y.DOM.hasClass(node, className)) { // skip if already present
5896
node.className = Y.Lang.trim([node.className, className].join(' '));
5901
* Removes a class name from a given element.
5902
* @method removeClass
5904
* @param {HTMLElement} element The DOM element.
5905
* @param {String} className the class name to remove from the class attribute
5907
removeClass: function(node, className) {
5908
if (className && hasClass(node, className)) {
5909
node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
5910
className + '(?:\\s+|$)'), ' '));
5912
if ( hasClass(node, className) ) { // in case of multiple adjacent
5913
removeClass(node, className);
5919
* Replace a class with another class for a given element.
5920
* If no oldClassName is present, the newClassName is simply added.
5921
* @method replaceClass
5923
* @param {HTMLElement} element The DOM element
5924
* @param {String} oldClassName the class name to be replaced
5925
* @param {String} newClassName the class name that will be replacing the old class name
5927
replaceClass: function(node, oldC, newC) {
5928
//Y.log('replaceClass replacing ' + oldC + ' with ' + newC, 'info', 'Node');
5929
removeClass(node, oldC); // remove first in case oldC === newC
5930
addClass(node, newC);
5934
* If the className exists on the node it is removed, if it doesn't exist it is added.
5935
* @method toggleClass
5937
* @param {HTMLElement} element The DOM element
5938
* @param {String} className the class name to be toggled
5939
* @param {Boolean} addClass optional boolean to indicate whether class
5940
* should be added or removed regardless of current state
5942
toggleClass: function(node, className, force) {
5943
var add = (force !== undefined) ? force :
5944
!(hasClass(node, className));
5947
addClass(node, className);
5949
removeClass(node, className);
5954
hasClass = Y.DOM.hasClass;
5955
removeClass = Y.DOM.removeClass;
5956
addClass = Y.DOM.addClass;
5958
var re_tag = /<([a-z]+)/i,
5962
addFeature = Y.Features.add,
5963
testFeature = Y.Features.test,
5967
createFromDIV = function(html, tag) {
5968
var div = Y.config.doc.createElement('div'),
5971
div.innerHTML = html;
5972
if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) {
5979
re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/,
5981
TABLE_OPEN = '<table>',
5982
TABLE_CLOSE = '</table>';
5987
_create: function(html, doc, tag) {
5990
var frag = Y_DOM._fragClones[tag];
5992
frag = frag.cloneNode(false);
5994
frag = Y_DOM._fragClones[tag] = doc.createElement(tag);
5996
frag.innerHTML = html;
6001
* Creates a new dom node using the provided markup string.
6003
* @param {String} html The markup used to create the element
6004
* @param {HTMLDocument} doc An optional document context
6005
* @return {HTMLElement|DocumentFragment} returns a single HTMLElement
6006
* when creating one node, and a documentFragment when creating
6009
create: function(html, doc) {
6010
if (typeof html === 'string') {
6011
html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
6015
doc = doc || Y.config.doc;
6016
var m = re_tag.exec(html),
6017
create = Y_DOM._create,
6023
if (html != undefined) { // not undefined or null
6025
creator = custom[m[1].toLowerCase()];
6026
if (typeof creator === 'function') {
6033
nodes = create(html, doc, tag).childNodes;
6035
if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
6036
ret = nodes[0].parentNode.removeChild(nodes[0]);
6037
} else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected)
6038
if (nodes.length === 2) {
6039
ret = nodes[0].nextSibling;
6041
nodes[0].parentNode.removeChild(nodes[0]);
6042
ret = Y_DOM._nl2frag(nodes, doc);
6044
} else { // return multiple nodes as a fragment
6045
ret = Y_DOM._nl2frag(nodes, doc);
6052
_nl2frag: function(nodes, doc) {
6056
if (nodes && (nodes.push || nodes.item) && nodes[0]) {
6057
doc = doc || nodes[0].ownerDocument;
6058
ret = doc.createDocumentFragment();
6060
if (nodes.item) { // convert live list to static array
6061
nodes = Y.Array(nodes, 0, true);
6064
for (i = 0, len = nodes.length; i < len; i++) {
6065
ret.appendChild(nodes[i]);
6067
} // else inline with log for minification
6068
else { Y.log('unable to convert ' + nodes + ' to fragment', 'warn', 'dom'); }
6073
* Inserts content in a node at the given location
6075
* @param {HTMLElement} node The node to insert into
6076
* @param {HTMLElement | Array | HTMLCollection} content The content to be inserted
6077
* @param {HTMLElement} where Where to insert the content
6078
* If no "where" is given, content is appended to the node
6079
* Possible values for "where"
6081
* <dt>HTMLElement</dt>
6082
* <dd>The element to insert before</dd>
6083
* <dt>"replace"</dt>
6084
* <dd>Replaces the existing HTML</dd>
6086
* <dd>Inserts before the existing HTML</dd>
6088
* <dd>Inserts content before the node</dd>
6090
* <dd>Inserts content after the node</dd>
6093
addHTML: function(node, content, where) {
6094
var nodeParent = node.parentNode,
6101
if (content != undefined) { // not null or undefined (maybe 0)
6102
if (content.nodeType) { // DOM node, just add it
6104
} else if (typeof content == 'string' || typeof content == 'number') {
6105
ret = newNode = Y_DOM.create(content);
6106
} else if (content[0] && content[0].nodeType) { // array or collection
6107
newNode = Y.config.doc.createDocumentFragment();
6108
while ((item = content[i++])) {
6109
newNode.appendChild(item); // append to fragment for insertion
6115
if (where.nodeType) { // insert regardless of relationship to node
6116
where.parentNode.insertBefore(newNode, where);
6120
while (node.firstChild) {
6121
node.removeChild(node.firstChild);
6123
if (newNode) { // allow empty content to clear node
6124
node.appendChild(newNode);
6128
nodeParent.insertBefore(newNode, node);
6131
if (node.nextSibling) { // IE errors if refNode is null
6132
nodeParent.insertBefore(newNode, node.nextSibling);
6134
nodeParent.appendChild(newNode);
6138
node.appendChild(newNode);
6141
} else if (newNode) {
6142
node.appendChild(newNode);
6149
addFeature('innerhtml', 'table', {
6151
var node = Y.config.doc.createElement('table');
6153
node.innerHTML = '<tbody></tbody>';
6157
return (node.firstChild && node.firstChild.nodeName === 'TBODY');
6161
addFeature('innerhtml-div', 'tr', {
6163
return createFromDIV('<tr></tr>', 'tr');
6167
addFeature('innerhtml-div', 'script', {
6169
return createFromDIV('<script></script>', 'script');
6173
if (!testFeature('innerhtml', 'table')) {
6174
// TODO: thead/tfoot with nested tbody
6175
// IE adds TBODY when creating TABLE elements (which may share this impl)
6176
creators.tbody = function(html, doc) {
6177
var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc),
6178
tb = frag.children.tags('tbody')[0];
6180
if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
6181
tb.parentNode.removeChild(tb); // strip extraneous tbody
6187
if (!testFeature('innerhtml-div', 'script')) {
6188
creators.script = function(html, doc) {
6189
var frag = doc.createElement('div');
6191
frag.innerHTML = '-' + html;
6192
frag.removeChild(frag.firstChild);
6196
creators.link = creators.style = creators.script;
6199
if (!testFeature('innerhtml-div', 'tr')) {
6201
option: function(html, doc) {
6202
return Y_DOM.create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc);
6205
tr: function(html, doc) {
6206
return Y_DOM.create('<tbody>' + html + '</tbody>', doc);
6209
td: function(html, doc) {
6210
return Y_DOM.create('<tr>' + html + '</tr>', doc);
6213
col: function(html, doc) {
6214
return Y_DOM.create('<colgroup>' + html + '</colgroup>', doc);
6223
thead: creators.tbody,
6224
tfoot: creators.tbody,
6225
caption: creators.tbody,
6226
colgroup: creators.tbody,
6227
optgroup: creators.option
6231
Y_DOM.creators = creators;
6234
* Sets the width of the element to the given size, regardless
6235
* of box model, border, padding, etc.
6237
* @param {HTMLElement} element The DOM element.
6238
* @param {String|Int} size The pixel height to size to
6241
setWidth: function(node, size) {
6242
Y.DOM._setSize(node, 'width', size);
6246
* Sets the height of the element to the given size, regardless
6247
* of box model, border, padding, etc.
6249
* @param {HTMLElement} element The DOM element.
6250
* @param {String|Int} size The pixel height to size to
6253
setHeight: function(node, size) {
6254
Y.DOM._setSize(node, 'height', size);
6257
_setSize: function(node, prop, val) {
6258
val = (val > 0) ? val : 0;
6261
node.style[prop] = val + 'px';
6262
size = (prop === 'height') ? node.offsetHeight : node.offsetWidth;
6265
val = val - (size - val);
6271
node.style[prop] = val + 'px';
6277
}, '3.4.1' ,{requires:['dom-core']});
6278
YUI.add('dom-style', function(Y) {
6282
* Add style management functionality to DOM.
6284
* @submodule dom-style
6288
var DOCUMENT_ELEMENT = 'documentElement',
6289
DEFAULT_VIEW = 'defaultView',
6290
OWNER_DOCUMENT = 'ownerDocument',
6293
CSS_FLOAT = 'cssFloat',
6294
STYLE_FLOAT = 'styleFloat',
6295
TRANSPARENT = 'transparent',
6296
GET_COMPUTED_STYLE = 'getComputedStyle',
6297
GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
6299
WINDOW = Y.config.win,
6300
DOCUMENT = Y.config.doc,
6301
UNDEFINED = undefined,
6305
TRANSFORM = 'transform',
6306
VENDOR_TRANSFORM = [
6312
re_color = /color$/i,
6313
re_unit = /width|height|top|left|right|bottom|margin|padding/i;
6315
Y.Array.each(VENDOR_TRANSFORM, function(val) {
6316
if (val in DOCUMENT[DOCUMENT_ELEMENT].style) {
6329
* Sets a style property for a given element.
6331
* @param {HTMLElement} An HTMLElement to apply the style to.
6332
* @param {String} att The style property to set.
6333
* @param {String|Number} val The value.
6335
setStyle: function(node, att, val, style) {
6336
style = style || node.style;
6337
var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES;
6340
if (val === null || val === '') { // normalize unsetting
6342
} else if (!isNaN(new Number(val)) && re_unit.test(att)) { // number values may need a unit
6343
val += Y_DOM.DEFAULT_UNIT;
6346
if (att in CUSTOM_STYLES) {
6347
if (CUSTOM_STYLES[att].set) {
6348
CUSTOM_STYLES[att].set(node, val, style);
6349
return; // NOTE: return
6350
} else if (typeof CUSTOM_STYLES[att] === 'string') {
6351
att = CUSTOM_STYLES[att];
6353
} else if (att === '') { // unset inline styles
6362
* Returns the current style value for the given property.
6364
* @param {HTMLElement} An HTMLElement to get the style from.
6365
* @param {String} att The style property to get.
6367
getStyle: function(node, att, style) {
6368
style = style || node.style;
6369
var CUSTOM_STYLES = Y_DOM.CUSTOM_STYLES,
6373
if (att in CUSTOM_STYLES) {
6374
if (CUSTOM_STYLES[att].get) {
6375
return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
6376
} else if (typeof CUSTOM_STYLES[att] === 'string') {
6377
att = CUSTOM_STYLES[att];
6381
if (val === '') { // TODO: is empty string sufficient?
6382
val = Y_DOM[GET_COMPUTED_STYLE](node, att);
6390
* Sets multiple style properties.
6392
* @param {HTMLElement} node An HTMLElement to apply the styles to.
6393
* @param {Object} hash An object literal of property:value pairs.
6395
setStyles: function(node, hash) {
6396
var style = node.style;
6397
Y.each(hash, function(v, n) {
6398
Y_DOM.setStyle(node, n, v, style);
6403
* Returns the computed style for the given node.
6404
* @method getComputedStyle
6405
* @param {HTMLElement} An HTMLElement to get the style from.
6406
* @param {String} att The style property to get.
6407
* @return {String} The computed value of the style property.
6409
getComputedStyle: function(node, att) {
6411
doc = node[OWNER_DOCUMENT];
6413
if (node[STYLE] && doc[DEFAULT_VIEW] && doc[DEFAULT_VIEW][GET_COMPUTED_STYLE]) {
6414
val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att];
6420
// normalize reserved word float alternatives ("cssFloat" or "styleFloat")
6421
if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) {
6422
Y_DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
6423
} else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) {
6424
Y_DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
6427
// fix opera computedStyle default color unit (convert to rgb)
6429
Y_DOM[GET_COMPUTED_STYLE] = function(node, att) {
6430
var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
6431
val = view[GET_COMPUTED_STYLE](node, '')[att];
6433
if (re_color.test(att)) {
6434
val = Y.Color.toRGB(val);
6442
// safari converts transparent to rgba(), others use "transparent"
6444
Y_DOM[GET_COMPUTED_STYLE] = function(node, att) {
6445
var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
6446
val = view[GET_COMPUTED_STYLE](node, '')[att];
6448
if (val === 'rgba(0, 0, 0, 0)') {
6457
Y.DOM._getAttrOffset = function(node, attr) {
6458
var val = Y.DOM[GET_COMPUTED_STYLE](node, attr),
6459
offsetParent = node.offsetParent,
6464
if (val === 'auto') {
6465
position = Y.DOM.getStyle(node, 'position');
6466
if (position === 'static' || position === 'relative') {
6468
} else if (offsetParent && offsetParent[GET_BOUNDING_CLIENT_RECT]) {
6469
parentOffset = offsetParent[GET_BOUNDING_CLIENT_RECT]()[attr];
6470
offset = node[GET_BOUNDING_CLIENT_RECT]()[attr];
6471
if (attr === 'left' || attr === 'top') {
6472
val = offset - parentOffset;
6474
val = parentOffset - node[GET_BOUNDING_CLIENT_RECT]()[attr];
6482
Y.DOM._getOffset = function(node) {
6487
pos = Y_DOM.getStyle(node, 'position');
6489
parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'left'), 10),
6490
parseInt(Y_DOM[GET_COMPUTED_STYLE](node, 'top'), 10)
6493
if ( isNaN(xy[0]) ) { // in case of 'auto'
6494
xy[0] = parseInt(Y_DOM.getStyle(node, 'left'), 10); // try inline
6495
if ( isNaN(xy[0]) ) { // default to offset value
6496
xy[0] = (pos === 'relative') ? 0 : node.offsetLeft || 0;
6500
if ( isNaN(xy[1]) ) { // in case of 'auto'
6501
xy[1] = parseInt(Y_DOM.getStyle(node, 'top'), 10); // try inline
6502
if ( isNaN(xy[1]) ) { // default to offset value
6503
xy[1] = (pos === 'relative') ? 0 : node.offsetTop || 0;
6512
Y_DOM.CUSTOM_STYLES.transform = {
6513
set: function(node, val, style) {
6514
style[TRANSFORM] = val;
6517
get: function(node, style) {
6518
return Y_DOM[GET_COMPUTED_STYLE](node, TRANSFORM);
6525
var PARSE_INT = parseInt,
6548
re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
6549
re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
6550
re_hex3: /([0-9A-F])/gi,
6552
toRGB: function(val) {
6553
if (!Y.Color.re_RGB.test(val)) {
6554
val = Y.Color.toHex(val);
6557
if(Y.Color.re_hex.exec(val)) {
6559
PARSE_INT(RE.$1, 16),
6560
PARSE_INT(RE.$2, 16),
6561
PARSE_INT(RE.$3, 16)
6567
toHex: function(val) {
6568
val = Y.Color.KEYWORDS[val] || val;
6569
if (Y.Color.re_RGB.exec(val)) {
6571
Number(RE.$1).toString(16),
6572
Number(RE.$2).toString(16),
6573
Number(RE.$3).toString(16)
6576
for (var i = 0; i < val.length; i++) {
6577
if (val[i].length < 2) {
6578
val[i] = '0' + val[i];
6585
if (val.length < 6) {
6586
val = val.replace(Y.Color.re_hex3, '$1$1');
6589
if (val !== 'transparent' && val.indexOf('#') < 0) {
6593
return val.toUpperCase();
6600
}, '3.4.1' ,{requires:['dom-base']});
6601
YUI.add('dom-style-ie', function(Y) {
6604
var HAS_LAYOUT = 'hasLayout',
6607
FILTERS = 'filters',
6608
OPACITY = 'opacity',
6611
BORDER_WIDTH = 'borderWidth',
6612
BORDER_TOP_WIDTH = 'borderTopWidth',
6613
BORDER_RIGHT_WIDTH = 'borderRightWidth',
6614
BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
6615
BORDER_LEFT_WIDTH = 'borderLeftWidth',
6618
TRANSPARENT = 'transparent',
6619
VISIBLE = 'visible',
6620
GET_COMPUTED_STYLE = 'getComputedStyle',
6621
UNDEFINED = undefined,
6622
documentElement = Y.config.doc.documentElement,
6624
testFeature = Y.Features.test,
6625
addFeature = Y.Features.add,
6627
// TODO: unit-less lineHeight (e.g. 1.22)
6628
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,
6630
isIE8 = (Y.UA.ie >= 8),
6632
_getStyleObj = function(node) {
6633
return node.currentStyle || node.style;
6639
get: function(el, property) {
6644
current = _getStyleObj(el)[property];
6646
if (property === OPACITY && Y.DOM.CUSTOM_STYLES[OPACITY]) {
6647
value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);
6648
} else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
6650
} else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
6651
value = Y.DOM.IE.COMPUTED[property](el, property);
6652
} else if (re_unit.test(current)) { // convert to pixel
6653
value = ComputedStyle.getPixel(el, property) + PX;
6663
width: ['Left', 'Right'],
6664
height: ['Top', 'Bottom'],
6669
getOffset: function(el, prop) {
6670
var current = _getStyleObj(el)[prop], // value of "width", "top", etc.
6671
capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
6672
offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc.
6673
pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc.
6674
sizeOffsets = ComputedStyle.sizeOffsets[prop],
6675
mode = el.ownerDocument.compatMode,
6678
// IE pixelWidth incorrect for percent
6679
// manually compute by subtracting padding and border from offset size
6680
// NOTE: clientWidth/Height (size minus border) is 0 when current === AUTO so offsetHeight is used
6681
// reverting to auto from auto causes position stacking issues (old impl)
6682
if (current === AUTO || current.indexOf('%') > -1) {
6683
value = el['offset' + capped];
6685
if (mode !== 'BackCompat') {
6686
if (sizeOffsets[0]) {
6687
value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[0]);
6688
value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[0] + 'Width', 1);
6691
if (sizeOffsets[1]) {
6692
value -= ComputedStyle.getPixel(el, 'padding' + sizeOffsets[1]);
6693
value -= ComputedStyle.getBorderWidth(el, 'border' + sizeOffsets[1] + 'Width', 1);
6697
} else { // use style.pixelWidth, etc. to convert to pixels
6698
// need to map style.width to currentStyle (no currentStyle.pixelWidth)
6699
if (!el.style[pixel] && !el.style[prop]) {
6700
el.style[prop] = current;
6702
value = el.style[pixel];
6709
thin: (isIE8) ? '1px' : '2px',
6710
medium: (isIE8) ? '3px': '4px',
6711
thick: (isIE8) ? '5px' : '6px'
6714
getBorderWidth: function(el, property, omitUnit) {
6715
var unit = omitUnit ? '' : PX,
6716
current = el.currentStyle[property];
6718
if (current.indexOf(PX) < 0) { // look up keywords if a border exists
6719
if (ComputedStyle.borderMap[current] &&
6720
el.currentStyle.borderStyle !== 'none') {
6721
current = ComputedStyle.borderMap[current];
6722
} else { // otherwise no border (default is "medium")
6726
return (omitUnit) ? parseFloat(current) : current;
6729
getPixel: function(node, att) {
6730
// use pixelRight to convert to px
6732
style = _getStyleObj(node),
6733
styleRight = style.right,
6734
current = style[att];
6736
node.style.right = current;
6737
val = node.style.pixelRight;
6738
node.style.right = styleRight; // revert
6743
getMargin: function(node, att) {
6745
style = _getStyleObj(node);
6747
if (style[att] == AUTO) {
6750
val = ComputedStyle.getPixel(node, att);
6755
getVisibility: function(node, att) {
6757
while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test
6758
node = node.parentNode;
6760
return (current) ? current[att] : VISIBLE;
6763
getColor: function(node, att) {
6764
var current = _getStyleObj(node)[att];
6766
if (!current || current === TRANSPARENT) {
6767
Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
6768
current = _getStyleObj(parent)[att];
6769
if (current && current !== TRANSPARENT) {
6776
return Y.Color.toRGB(current);
6779
getBorderColor: function(node, att) {
6780
var current = _getStyleObj(node),
6781
val = current[att] || current.color;
6782
return Y.Color.toRGB(Y.Color.toHex(val));
6786
//fontSize: getPixelFont,
6789
addFeature('style', 'computedStyle', {
6791
return 'getComputedStyle' in Y.config.win;
6795
addFeature('style', 'opacity', {
6797
return 'opacity' in documentElement.style;
6801
addFeature('style', 'filter', {
6803
return 'filters' in documentElement;
6807
// use alpha filter for IE opacity
6808
if (!testFeature('style', 'opacity') && testFeature('style', 'filter')) {
6809
Y.DOM.CUSTOM_STYLES[OPACITY] = {
6810
get: function(node) {
6812
try { // will error if no DXImageTransform
6813
val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
6816
try { // make sure its in the document
6817
val = node[FILTERS]('alpha')[OPACITY];
6819
Y.log('getStyle: IE opacity filter not found; returning 1', 'warn', 'dom-style');
6825
set: function(node, val, style) {
6827
styleObj = _getStyleObj(node),
6828
currentFilter = styleObj[FILTER];
6830
style = style || node.style;
6831
if (val === '') { // normalize inline style behavior
6832
current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
6836
if (typeof currentFilter == 'string') { // in case not appended
6837
style[FILTER] = currentFilter.replace(/alpha([^)]*\))/gi, '') +
6838
((val < 1) ? 'alpha(' + OPACITY + '=' + val * 100 + ')' : '');
6840
if (!style[FILTER]) {
6841
style.removeAttribute(FILTER);
6844
if (!styleObj[HAS_LAYOUT]) {
6845
style.zoom = 1; // needs layout
6853
Y.config.doc.createElement('div').style.height = '-1px';
6854
} catch(e) { // IE throws error on invalid style set; trap common cases
6855
Y.DOM.CUSTOM_STYLES.height = {
6856
set: function(node, val, style) {
6857
var floatVal = parseFloat(val);
6858
if (floatVal >= 0 || val === 'auto' || val === '') {
6861
Y.log('invalid style value for height: ' + val, 'warn', 'dom-style');
6866
Y.DOM.CUSTOM_STYLES.width = {
6867
set: function(node, val, style) {
6868
var floatVal = parseFloat(val);
6869
if (floatVal >= 0 || val === 'auto' || val === '') {
6872
Y.log('invalid style value for width: ' + val, 'warn', 'dom-style');
6878
if (!testFeature('style', 'computedStyle')) {
6879
// TODO: top, right, bottom, left
6880
IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
6882
IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
6884
IEComputed[BORDER_WIDTH] = IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
6885
IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
6886
ComputedStyle.getBorderWidth;
6888
IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
6889
IEComputed.marginLeft = ComputedStyle.getMargin;
6891
IEComputed.visibility = ComputedStyle.getVisibility;
6892
IEComputed.borderColor = IEComputed.borderTopColor =
6893
IEComputed.borderRightColor = IEComputed.borderBottomColor =
6894
IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
6896
Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get;
6898
Y.namespace('DOM.IE');
6899
Y.DOM.IE.COMPUTED = IEComputed;
6900
Y.DOM.IE.ComputedStyle = ComputedStyle;
6906
}, '3.4.1' ,{requires:['dom-style']});
6907
YUI.add('dom-screen', function(Y) {
6912
* Adds position and region management functionality to DOM.
6914
* @submodule dom-screen
6918
var DOCUMENT_ELEMENT = 'documentElement',
6919
COMPAT_MODE = 'compatMode',
6920
POSITION = 'position',
6922
RELATIVE = 'relative',
6925
_BACK_COMPAT = 'BackCompat',
6927
BORDER_LEFT_WIDTH = 'borderLeftWidth',
6928
BORDER_TOP_WIDTH = 'borderTopWidth',
6929
GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect',
6930
GET_COMPUTED_STYLE = 'getComputedStyle',
6934
// TODO: how about thead/tbody/tfoot/tr?
6935
// TODO: does caption matter?
6936
RE_TABLE = /^t(?:able|d|h)$/i,
6941
if (Y.config.doc[COMPAT_MODE] !== 'BackCompat') {
6942
SCROLL_NODE = DOCUMENT_ELEMENT;
6944
SCROLL_NODE = 'body';
6950
* Returns the inner height of the viewport (exludes scrollbar).
6952
* @return {Number} The current height of the viewport.
6954
winHeight: function(node) {
6955
var h = Y_DOM._getWinSize(node).height;
6956
Y.log('winHeight returning ' + h, 'info', 'dom-screen');
6961
* Returns the inner width of the viewport (exludes scrollbar).
6963
* @return {Number} The current width of the viewport.
6965
winWidth: function(node) {
6966
var w = Y_DOM._getWinSize(node).width;
6967
Y.log('winWidth returning ' + w, 'info', 'dom-screen');
6974
* @return {Number} The current height of the document.
6976
docHeight: function(node) {
6977
var h = Y_DOM._getDocSize(node).height;
6978
Y.log('docHeight returning ' + h, 'info', 'dom-screen');
6979
return Math.max(h, Y_DOM._getWinSize(node).height);
6985
* @return {Number} The current width of the document.
6987
docWidth: function(node) {
6988
var w = Y_DOM._getDocSize(node).width;
6989
Y.log('docWidth returning ' + w, 'info', 'dom-screen');
6990
return Math.max(w, Y_DOM._getWinSize(node).width);
6994
* Amount page has been scroll horizontally
6995
* @method docScrollX
6996
* @return {Number} The current amount the screen is scrolled horizontally.
6998
docScrollX: function(node, doc) {
6999
doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
7000
var dv = doc.defaultView,
7001
pageOffset = (dv) ? dv.pageXOffset : 0;
7002
return Math.max(doc[DOCUMENT_ELEMENT].scrollLeft, doc.body.scrollLeft, pageOffset);
7006
* Amount page has been scroll vertically
7007
* @method docScrollY
7008
* @return {Number} The current amount the screen is scrolled vertically.
7010
docScrollY: function(node, doc) {
7011
doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc; // perf optimization
7012
var dv = doc.defaultView,
7013
pageOffset = (dv) ? dv.pageYOffset : 0;
7014
return Math.max(doc[DOCUMENT_ELEMENT].scrollTop, doc.body.scrollTop, pageOffset);
7018
* Gets the current position of an element based on page coordinates.
7019
* Element must be part of the DOM tree to have page coordinates
7020
* (display:none or elements not appended return false).
7022
* @param element The target element
7023
* @return {Array} The XY position of the element
7025
TODO: test inDocument/display?
7028
if (Y.config.doc[DOCUMENT_ELEMENT][GET_BOUNDING_CLIENT_RECT]) {
7029
return function(node) {
7041
if (node && node.tagName) {
7042
doc = node.ownerDocument;
7043
rootNode = doc[DOCUMENT_ELEMENT];
7045
// inline inDoc check for perf
7046
if (rootNode.contains) {
7047
inDoc = rootNode.contains(node);
7049
inDoc = Y.DOM.contains(rootNode, node);
7053
scrollLeft = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollLeft : Y_DOM.docScrollX(node, doc);
7054
scrollTop = (SCROLL_NODE) ? doc[SCROLL_NODE].scrollTop : Y_DOM.docScrollY(node, doc);
7055
box = node[GET_BOUNDING_CLIENT_RECT]();
7056
xy = [box.left, box.top];
7061
mode = doc[COMPAT_MODE];
7062
bLeft = Y_DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_LEFT_WIDTH);
7063
bTop = Y_DOM[GET_COMPUTED_STYLE](doc[DOCUMENT_ELEMENT], BORDER_TOP_WIDTH);
7065
if (Y.UA.ie === 6) {
7066
if (mode !== _BACK_COMPAT) {
7072
if ((mode == _BACK_COMPAT)) {
7073
if (bLeft !== MEDIUM) {
7074
off1 = parseInt(bLeft, 10);
7076
if (bTop !== MEDIUM) {
7077
off2 = parseInt(bTop, 10);
7086
if ((scrollTop || scrollLeft)) {
7087
if (!Y.UA.ios || (Y.UA.ios >= 4.2)) {
7088
xy[0] += scrollLeft;
7094
xy = Y_DOM._getOffset(node);
7100
return function(node) { // manually calculate by crawling up offsetParents
7101
//Calculate the Top and Left border sizes (assumes pixels)
7110
if (Y_DOM.inDoc(node)) {
7111
xy = [node.offsetLeft, node.offsetTop];
7112
doc = node.ownerDocument;
7114
// TODO: refactor with !! or just falsey
7115
bCheck = ((Y.UA.gecko || Y.UA.webkit > 519) ? true : false);
7117
// TODO: worth refactoring for TOP/LEFT only?
7118
while ((parentNode = parentNode.offsetParent)) {
7119
xy[0] += parentNode.offsetLeft;
7120
xy[1] += parentNode.offsetTop;
7122
xy = Y_DOM._calcBorders(parentNode, xy);
7126
// account for any scrolled ancestors
7127
if (Y_DOM.getStyle(node, POSITION) != FIXED) {
7130
while ((parentNode = parentNode.parentNode)) {
7131
scrollTop = parentNode.scrollTop;
7132
scrollLeft = parentNode.scrollLeft;
7134
//Firefox does something funky with borders when overflow is not visible.
7135
if (Y.UA.gecko && (Y_DOM.getStyle(parentNode, 'overflow') !== 'visible')) {
7136
xy = Y_DOM._calcBorders(parentNode, xy);
7140
if (scrollTop || scrollLeft) {
7141
xy[0] -= scrollLeft;
7145
xy[0] += Y_DOM.docScrollX(node, doc);
7146
xy[1] += Y_DOM.docScrollY(node, doc);
7149
//Fix FIXED position -- add scrollbars
7150
xy[0] += Y_DOM.docScrollX(node, doc);
7151
xy[1] += Y_DOM.docScrollY(node, doc);
7154
xy = Y_DOM._getOffset(node);
7161
}(),// NOTE: Executing for loadtime branching
7164
* Gets the current X position of an element based on page coordinates.
7165
* Element must be part of the DOM tree to have page coordinates
7166
* (display:none or elements not appended return false).
7168
* @param element The target element
7169
* @return {Int} The X position of the element
7172
getX: function(node) {
7173
return Y_DOM.getXY(node)[0];
7177
* Gets the current Y position of an element based on page coordinates.
7178
* Element must be part of the DOM tree to have page coordinates
7179
* (display:none or elements not appended return false).
7181
* @param element The target element
7182
* @return {Int} The Y position of the element
7185
getY: function(node) {
7186
return Y_DOM.getXY(node)[1];
7190
* Set the position of an html element in page coordinates.
7191
* The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7193
* @param element The target element
7194
* @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
7195
* @param {Boolean} noRetry By default we try and set the position a second time if the first fails
7197
setXY: function(node, xy, noRetry) {
7198
var setStyle = Y_DOM.setStyle,
7205
pos = Y_DOM.getStyle(node, POSITION);
7207
delta = Y_DOM._getOffset(node);
7208
if (pos == 'static') { // default to relative
7210
setStyle(node, POSITION, pos);
7212
currentXY = Y_DOM.getXY(node);
7214
if (xy[0] !== null) {
7215
setStyle(node, LEFT, xy[0] - currentXY[0] + delta[0] + 'px');
7218
if (xy[1] !== null) {
7219
setStyle(node, TOP, xy[1] - currentXY[1] + delta[1] + 'px');
7223
newXY = Y_DOM.getXY(node);
7224
if (newXY[0] !== xy[0] || newXY[1] !== xy[1]) {
7225
Y_DOM.setXY(node, xy, true);
7229
Y.log('setXY setting position to ' + xy, 'info', 'dom-screen');
7231
Y.log('setXY failed to set ' + node + ' to ' + xy, 'info', 'dom-screen');
7236
* Set the X position of an html element in page coordinates, regardless of how the element is positioned.
7237
* The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7239
* @param element The target element
7240
* @param {Int} x The X values for new position (coordinates are page-based)
7242
setX: function(node, x) {
7243
return Y_DOM.setXY(node, [x, null]);
7247
* Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
7248
* The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7250
* @param element The target element
7251
* @param {Int} y The Y values for new position (coordinates are page-based)
7253
setY: function(node, y) {
7254
return Y_DOM.setXY(node, [null, y]);
7259
* @description Swap the xy position with another node
7260
* @param {Node} node The node to swap with
7261
* @param {Node} otherNode The other node to swap with
7264
swapXY: function(node, otherNode) {
7265
var xy = Y_DOM.getXY(node);
7266
Y_DOM.setXY(node, Y_DOM.getXY(otherNode));
7267
Y_DOM.setXY(otherNode, xy);
7270
_calcBorders: function(node, xy2) {
7271
var t = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_TOP_WIDTH), 10) || 0,
7272
l = parseInt(Y_DOM[GET_COMPUTED_STYLE](node, BORDER_LEFT_WIDTH), 10) || 0;
7274
if (RE_TABLE.test(node.tagName)) {
7284
_getWinSize: function(node, doc) {
7285
doc = doc || (node) ? Y_DOM._getDoc(node) : Y.config.doc;
7286
var win = doc.defaultView || doc.parentWindow,
7287
mode = doc[COMPAT_MODE],
7288
h = win.innerHeight,
7290
root = doc[DOCUMENT_ELEMENT];
7292
if ( mode && !Y.UA.opera ) { // IE, Gecko
7293
if (mode != 'CSS1Compat') { // Quirks
7296
h = root.clientHeight;
7297
w = root.clientWidth;
7299
return { height: h, width: w };
7302
_getDocSize: function(node) {
7303
var doc = (node) ? Y_DOM._getDoc(node) : Y.config.doc,
7304
root = doc[DOCUMENT_ELEMENT];
7306
if (doc[COMPAT_MODE] != 'CSS1Compat') {
7310
return { height: root.scrollHeight, width: root.scrollWidth };
7321
getOffsets = function(r1, r2) {
7322
var t = Math.max(r1[TOP], r2[TOP]),
7323
r = Math.min(r1[RIGHT], r2[RIGHT]),
7324
b = Math.min(r1[BOTTOM], r2[BOTTOM]),
7325
l = Math.max(r1[LEFT], r2[LEFT]),
7339
* Returns an Object literal containing the following about this element: (top, right, bottom, left)
7342
* @param {HTMLElement} element The DOM element.
7343
* @return {Object} Object literal containing the following about this element: (top, right, bottom, left)
7345
region: function(node) {
7346
var xy = DOM.getXY(node),
7350
ret = DOM._getRegion(
7352
xy[0] + node.offsetWidth, // right
7353
xy[1] + node.offsetHeight, // bottom
7362
* Find the intersect information for the passes nodes.
7365
* @param {HTMLElement} element The first element
7366
* @param {HTMLElement | Object} element2 The element or region to check the interect with
7367
* @param {Object} altRegion An object literal containing the region for the first element if we already have the data (for performance i.e. DragDrop)
7368
* @return {Object} Object literal containing the following intersection data: (top, right, bottom, left, area, yoff, xoff, inRegion)
7370
intersect: function(node, node2, altRegion) {
7371
var r = altRegion || DOM.region(node), region = {},
7376
region = DOM.region(n);
7377
} else if (Y.Lang.isObject(node2)) {
7383
off = getOffsets(region, r);
7387
bottom: off[BOTTOM],
7389
area: ((off[BOTTOM] - off[TOP]) * (off[RIGHT] - off[LEFT])),
7390
yoff: ((off[BOTTOM] - off[TOP])),
7391
xoff: (off[RIGHT] - off[LEFT]),
7392
inRegion: DOM.inRegion(node, node2, false, altRegion)
7397
* Check if any part of this node is in the passed region
7400
* @param {Object} node2 The node to get the region from or an Object literal of the region
7401
* $param {Boolean} all Should all of the node be inside the region
7402
* @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
7403
* @return {Boolean} True if in region, false if not.
7405
inRegion: function(node, node2, all, altRegion) {
7407
r = altRegion || DOM.region(node),
7412
region = DOM.region(n);
7413
} else if (Y.Lang.isObject(node2)) {
7421
r[LEFT] >= region[LEFT] &&
7422
r[RIGHT] <= region[RIGHT] &&
7423
r[TOP] >= region[TOP] &&
7424
r[BOTTOM] <= region[BOTTOM] );
7426
off = getOffsets(region, r);
7427
if (off[BOTTOM] >= off[TOP] && off[RIGHT] >= off[LEFT]) {
7437
* Check if any part of this element is in the viewport
7438
* @method inViewportRegion
7440
* @param {HTMLElement} element The DOM element.
7441
* @param {Boolean} all Should all of the node be inside the region
7442
* @param {Object} altRegion An object literal containing the region for this node if we already have the data (for performance i.e. DragDrop)
7443
* @return {Boolean} True if in region, false if not.
7445
inViewportRegion: function(node, all, altRegion) {
7446
return DOM.inRegion(node, DOM.viewportRegion(node), all, altRegion);
7450
_getRegion: function(t, r, b, l) {
7453
region[TOP] = region[1] = t;
7454
region[LEFT] = region[0] = l;
7457
region.width = region[RIGHT] - region[LEFT];
7458
region.height = region[BOTTOM] - region[TOP];
7464
* Returns an Object literal containing the following about the visible region of viewport: (top, right, bottom, left)
7465
* @method viewportRegion
7467
* @return {Object} Object literal containing the following about the visible region of the viewport: (top, right, bottom, left)
7469
viewportRegion: function(node) {
7470
node = node || Y.config.doc.documentElement;
7476
scrollX = DOM.docScrollX(node);
7477
scrollY = DOM.docScrollY(node);
7479
ret = DOM._getRegion(scrollY, // top
7480
DOM.winWidth(node) + scrollX, // right
7481
scrollY + DOM.winHeight(node), // bottom
7491
}, '3.4.1' ,{requires:['dom-base', 'dom-style']});
7492
YUI.add('selector-native', function(Y) {
7496
* The selector-native module provides support for native querySelector
7498
* @submodule selector-native
7503
* Provides support for using CSS selectors to query the DOM
7509
Y.namespace('Selector'); // allow native module to standalone
7511
var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
7512
OWNER_DOCUMENT = 'ownerDocument';
7519
_compare: ('sourceIndex' in Y.config.doc.documentElement) ?
7520
function(nodeA, nodeB) {
7521
var a = nodeA.sourceIndex,
7522
b = nodeB.sourceIndex;
7532
} : (Y.config.doc.documentElement[COMPARE_DOCUMENT_POSITION] ?
7533
function(nodeA, nodeB) {
7534
if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
7540
function(nodeA, nodeB) {
7541
var rangeA, rangeB, compare;
7542
if (nodeA && nodeB) {
7543
rangeA = nodeA[OWNER_DOCUMENT].createRange();
7544
rangeA.setStart(nodeA, 0);
7545
rangeB = nodeB[OWNER_DOCUMENT].createRange();
7546
rangeB.setStart(nodeB, 0);
7547
compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
7554
_sort: function(nodes) {
7556
nodes = Y.Array(nodes, 0, true);
7558
nodes.sort(Selector._compare);
7565
_deDupe: function(nodes) {
7569
for (i = 0; (node = nodes[i++]);) {
7571
ret[ret.length] = node;
7576
for (i = 0; (node = ret[i++]);) {
7578
node.removeAttribute('_found');
7585
* Retrieves a set of nodes based on a given CSS selector.
7588
* @param {string} selector The CSS Selector to test the node against.
7589
* @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
7590
* @param {Boolean} firstOnly optional Whether or not to return only the first match.
7591
* @return {Array} An array of nodes that match the given selector.
7594
query: function(selector, root, firstOnly, skipNative) {
7595
root = root || Y.config.doc;
7597
useNative = (Y.Selector.useNative && Y.config.doc.querySelector && !skipNative),
7598
queries = [[selector, root]],
7602
fn = (useNative) ? Y.Selector._nativeQuery : Y.Selector._bruteQuery;
7604
if (selector && fn) {
7605
// split group into seperate queries
7606
if (!skipNative && // already done if skipping
7607
(!useNative || root.tagName)) { // split native when element scoping is needed
7608
queries = Selector._splitQueries(selector, root);
7611
for (i = 0; (query = queries[i++]);) {
7612
result = fn(query[0], query[1], firstOnly);
7613
if (!firstOnly) { // coerce DOM Collection to Array
7614
result = Y.Array(result, 0, true);
7617
ret = ret.concat(result);
7621
if (queries.length > 1) { // remove dupes and sort by doc order
7622
ret = Selector._sort(Selector._deDupe(ret));
7626
Y.log('query: ' + selector + ' returning: ' + ret.length, 'info', 'Selector');
7627
return (firstOnly) ? (ret[0] || null) : ret;
7631
// allows element scoped queries to begin with combinator
7632
// e.g. query('> p', document.body) === query('body > p')
7633
_splitQueries: function(selector, node) {
7634
var groups = selector.split(','),
7640
// enforce for element scoping
7642
node.id = node.id || Y.guid();
7643
prefix = '[id="' + node.id + '"] ';
7646
for (i = 0, len = groups.length; i < len; ++i) {
7647
selector = prefix + groups[i];
7648
queries.push([selector, node]);
7655
_nativeQuery: function(selector, root, one) {
7656
if (Y.UA.webkit && selector.indexOf(':checked') > -1 &&
7657
(Y.Selector.pseudos && Y.Selector.pseudos.checked)) { // webkit (chrome, safari) fails to pick up "selected" with "checked"
7658
return Y.Selector.query(selector, root, one, true); // redo with skipNative true to try brute query
7661
//Y.log('trying native query with: ' + selector, 'info', 'selector-native');
7662
return root['querySelector' + (one ? '' : 'All')](selector);
7663
} catch(e) { // fallback to brute if available
7664
//Y.log('native query error; reverting to brute query with: ' + selector, 'info', 'selector-native');
7665
return Y.Selector.query(selector, root, one, true); // redo with skipNative true
7669
filter: function(nodes, selector) {
7673
if (nodes && selector) {
7674
for (i = 0; (node = nodes[i++]);) {
7675
if (Y.Selector.test(node, selector)) {
7676
ret[ret.length] = node;
7680
Y.log('invalid filter input (nodes: ' + nodes +
7681
', selector: ' + selector + ')', 'warn', 'Selector');
7687
test: function(node, selector, root) {
7697
if (node && node.tagName) { // only test HTMLElements
7699
if (typeof selector == 'function') { // test with function
7700
ret = selector.call(node, node);
7701
} else { // test with query
7702
// we need a root if off-doc
7703
groups = selector.split(',');
7704
if (!root && !Y.DOM.inDoc(node)) {
7705
parent = node.parentNode;
7708
} else { // only use frag when no parent to query
7709
frag = node[OWNER_DOCUMENT].createDocumentFragment();
7710
frag.appendChild(node);
7715
root = root || node[OWNER_DOCUMENT];
7720
for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
7721
group += '[id="' + node.id + '"]';
7722
items = Y.Selector.query(group, root);
7724
for (j = 0; item = items[j++];) {
7725
if (item === node) {
7735
if (useFrag) { // cleanup
7736
frag.removeChild(node);
7745
* A convenience function to emulate Y.Node's aNode.ancestor(selector).
7746
* @param {HTMLElement} element An HTMLElement to start the query from.
7747
* @param {String} selector The CSS selector to test the node against.
7748
* @return {HTMLElement} The ancestor node matching the selector, or null.
7749
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
7753
ancestor: function (element, selector, testSelf) {
7754
return Y.DOM.ancestor(element, function(n) {
7755
return Y.Selector.test(n, selector);
7760
Y.mix(Y.Selector, Selector, true);
7765
}, '3.4.1' ,{requires:['dom-base']});
7766
YUI.add('selector', function(Y) {
7771
}, '3.4.1' ,{requires:['selector-native']});
7772
YUI.add('event-custom-base', function(Y) {
7775
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
7777
* @module event-custom
7787
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
7789
* @module event-custom
7790
* @submodule event-custom-base
7794
* Allows for the insertion of methods that are executed before or after
7795
* a specified method
7806
* Cache of objects touched by the utility
7813
* <p>Execute the supplied method before the specified function. Wrapping
7814
* function may optionally return an instance of the following classes to
7815
* further alter runtime behavior:</p>
7817
* <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
7818
* <dd>Immediatly stop execution and return
7819
* <code>returnValue</code>. No other wrapping functions will be
7821
* <dt></code>Y.Do.AlterArgs(message, newArgArray)</code></dt>
7822
* <dd>Replace the arguments that the original function will be
7824
* <dt></code>Y.Do.Prevent(message)</code></dt>
7825
* <dd>Don't execute the wrapped function. Other before phase
7826
* wrappers will be executed.</dd>
7830
* @param fn {Function} the function to execute
7831
* @param obj the object hosting the method to displace
7832
* @param sFn {string} the name of the method to displace
7833
* @param c The execution context for fn
7834
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
7835
* when the event fires.
7836
* @return {string} handle for the subscription
7839
before: function(fn, obj, sFn, c) {
7840
// Y.log('Do before: ' + sFn, 'info', 'event');
7843
a = [fn, c].concat(Y.Array(arguments, 4, true));
7844
f = Y.rbind.apply(Y, a);
7847
return this._inject(DO_BEFORE, f, obj, sFn);
7851
* <p>Execute the supplied method after the specified function. Wrapping
7852
* function may optionally return an instance of the following classes to
7853
* further alter runtime behavior:</p>
7855
* <dt></code>Y.Do.Halt(message, returnValue)</code></dt>
7856
* <dd>Immediatly stop execution and return
7857
* <code>returnValue</code>. No other wrapping functions will be
7859
* <dt></code>Y.Do.AlterReturn(message, returnValue)</code></dt>
7860
* <dd>Return <code>returnValue</code> instead of the wrapped
7861
* method's original return value. This can be further altered by
7862
* other after phase wrappers.</dd>
7865
* <p>The static properties <code>Y.Do.originalRetVal</code> and
7866
* <code>Y.Do.currentRetVal</code> will be populated for reference.</p>
7869
* @param fn {Function} the function to execute
7870
* @param obj the object hosting the method to displace
7871
* @param sFn {string} the name of the method to displace
7872
* @param c The execution context for fn
7873
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
7874
* @return {string} handle for the subscription
7877
after: function(fn, obj, sFn, c) {
7880
a = [fn, c].concat(Y.Array(arguments, 4, true));
7881
f = Y.rbind.apply(Y, a);
7884
return this._inject(DO_AFTER, f, obj, sFn);
7888
* Execute the supplied method before or after the specified function.
7889
* Used by <code>before</code> and <code>after</code>.
7892
* @param when {string} before or after
7893
* @param fn {Function} the function to execute
7894
* @param obj the object hosting the method to displace
7895
* @param sFn {string} the name of the method to displace
7896
* @param c The execution context for fn
7897
* @return {string} handle for the subscription
7901
_inject: function(when, fn, obj, sFn) {
7904
var id = Y.stamp(obj), o, sid;
7906
if (! this.objs[id]) {
7907
// create a map entry for the obj if it doesn't exist
7914
// create a map entry for the method if it doesn't exist
7915
o[sFn] = new Y.Do.Method(obj, sFn);
7917
// re-route the method to our wrapper
7920
return o[sFn].exec.apply(o[sFn], arguments);
7925
sid = id + Y.stamp(fn) + sFn;
7927
// register the callback
7928
o[sFn].register(sid, fn, when);
7930
return new Y.EventHandle(o[sFn], sid);
7935
* Detach a before or after subscription.
7938
* @param handle {string} the subscription handle
7941
detach: function(handle) {
7943
if (handle.detach) {
7949
_unload: function(e, me) {
7956
//////////////////////////////////////////////////////////////////////////
7959
* Contains the return value from the wrapped method, accessible
7960
* by 'after' event listeners.
7962
* @property Do.originalRetVal
7968
* Contains the current state of the return value, consumable by
7969
* 'after' event listeners, and updated if an after subscriber
7970
* changes the return value generated by the wrapped function.
7972
* @property Do.currentRetVal
7977
//////////////////////////////////////////////////////////////////////////
7980
* Wrapper for a displaced method with aop enabled
7983
* @param obj The object to operate on
7984
* @param sFn The name of the method to displace
7986
DO.Method = function(obj, sFn) {
7988
this.methodName = sFn;
7989
this.method = obj[sFn];
7995
* Register a aop subscriber
7997
* @param sid {string} the subscriber id
7998
* @param fn {Function} the function to execute
7999
* @param when {string} when to execute the function
8001
DO.Method.prototype.register = function (sid, fn, when) {
8003
this.after[sid] = fn;
8005
this.before[sid] = fn;
8010
* Unregister a aop subscriber
8012
* @param sid {string} the subscriber id
8013
* @param fn {Function} the function to execute
8014
* @param when {string} when to execute the function
8016
DO.Method.prototype._delete = function (sid) {
8017
// Y.log('Y.Do._delete: ' + sid, 'info', 'Event');
8018
delete this.before[sid];
8019
delete this.after[sid];
8023
* <p>Execute the wrapped method. All arguments are passed into the wrapping
8024
* functions. If any of the before wrappers return an instance of
8025
* <code>Y.Do.Halt</code> or <code>Y.Do.Prevent</code>, neither the wrapped
8026
* function nor any after phase subscribers will be executed.</p>
8028
* <p>The return value will be the return value of the wrapped function or one
8029
* provided by a wrapper function via an instance of <code>Y.Do.Halt</code> or
8030
* <code>Y.Do.AlterReturn</code>.
8033
* @param arg* {any} Arguments are passed to the wrapping and wrapped functions
8034
* @return {any} Return value of wrapped function unless overwritten (see above)
8036
DO.Method.prototype.exec = function () {
8038
var args = Y.Array(arguments, 0, true),
8046
if (bf.hasOwnProperty(i)) {
8047
ret = bf[i].apply(this.obj, args);
8049
switch (ret.constructor) {
8066
ret = this.method.apply(this.obj, args);
8069
DO.originalRetVal = ret;
8070
DO.currentRetVal = ret;
8072
// execute after methods.
8074
if (af.hasOwnProperty(i)) {
8075
newRet = af[i].apply(this.obj, args);
8076
// Stop processing if a Halt object is returned
8077
if (newRet && newRet.constructor == DO.Halt) {
8078
return newRet.retVal;
8079
// Check for a new return value
8080
} else if (newRet && newRet.constructor == DO.AlterReturn) {
8081
ret = newRet.newRetVal;
8082
// Update the static retval state
8083
DO.currentRetVal = ret;
8091
//////////////////////////////////////////////////////////////////////////
8094
* Return an AlterArgs object when you want to change the arguments that
8095
* were passed into the function. Useful for Do.before subscribers. An
8096
* example would be a service that scrubs out illegal characters prior to
8097
* executing the core business logic.
8098
* @class Do.AlterArgs
8100
* @param msg {String} (optional) Explanation of the altered return value
8101
* @param newArgs {Array} Call parameters to be used for the original method
8102
* instead of the arguments originally passed in.
8104
DO.AlterArgs = function(msg, newArgs) {
8106
this.newArgs = newArgs;
8110
* Return an AlterReturn object when you want to change the result returned
8111
* from the core method to the caller. Useful for Do.after subscribers.
8112
* @class Do.AlterReturn
8114
* @param msg {String} (optional) Explanation of the altered return value
8115
* @param newRetVal {any} Return value passed to code that invoked the wrapped
8118
DO.AlterReturn = function(msg, newRetVal) {
8120
this.newRetVal = newRetVal;
8124
* Return a Halt object when you want to terminate the execution
8125
* of all subsequent subscribers as well as the wrapped method
8126
* if it has not exectued yet. Useful for Do.before subscribers.
8129
* @param msg {String} (optional) Explanation of why the termination was done
8130
* @param retVal {any} Return value passed to code that invoked the wrapped
8133
DO.Halt = function(msg, retVal) {
8135
this.retVal = retVal;
8139
* Return a Prevent object when you want to prevent the wrapped function
8140
* from executing, but want the remaining listeners to execute. Useful
8141
* for Do.before subscribers.
8144
* @param msg {String} (optional) Explanation of why the termination was done
8146
DO.Prevent = function(msg) {
8151
* Return an Error object when you want to terminate the execution
8152
* of all subsequent method calls.
8155
* @param msg {String} (optional) Explanation of the altered return value
8156
* @param retVal {any} Return value passed to code that invoked the wrapped
8158
* @deprecated use Y.Do.Halt or Y.Do.Prevent
8163
//////////////////////////////////////////////////////////////////////////
8165
// Y["Event"] && Y.Event.addListener(window, "unload", Y.Do._unload, Y.Do);
8169
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
8171
* @module event-custom
8172
* @submodule event-custom-base
8176
// var onsubscribeType = "_event:onsub",
8177
var AFTER = 'after',
8186
'defaultTargetOnly',
8202
YUI_LOG = 'yui:log';
8205
* The CustomEvent class lets you define events for your application
8206
* that can be subscribed to by one or more independent component.
8208
* @param {String} type The type of event, which is passed to the callback
8209
* when the event fires.
8210
* @param {object} o configuration object.
8211
* @class CustomEvent
8214
Y.CustomEvent = function(type, o) {
8216
// if (arguments.length > 2) {
8217
// this.log('CustomEvent context and silent are now in the config', 'warn', 'Event');
8222
this.id = Y.stamp(this);
8225
* The type of event, returned to subscribers when the event fires
8232
* The context the the event will fire from by default. Defaults to the YUI
8240
* Monitor when an event is attached or detached.
8242
* @property monitored
8245
// this.monitored = false;
8247
this.logSystem = (type == YUI_LOG);
8250
* If 0, this event does not broadcast. If 1, the YUI instance is notified
8251
* every time this event fires. If 2, the YUI instance and the YUI global
8252
* (if event is enabled on the global) are notified every time this event
8254
* @property broadcast
8257
// this.broadcast = 0;
8260
* By default all custom events are logged in the debug build, set silent
8261
* to true to disable debug outpu for this event.
8265
this.silent = this.logSystem;
8268
* Specifies whether this event should be queued when the host is actively
8269
* processing an event. This will effect exectution order of the callbacks
8270
* for the various events.
8271
* @property queuable
8275
// this.queuable = false;
8278
* The subscribers to this event
8279
* @property subscribers
8280
* @type Subscriber {}
8282
this.subscribers = {};
8285
* 'After' subscribers
8287
* @type Subscriber {}
8292
* This event has fired if true
8298
// this.fired = false;
8301
* An array containing the arguments the custom event
8302
* was last fired with.
8303
* @property firedWith
8309
* This event should only fire one time if true, and if
8310
* it has fired, any new subscribers should be notified
8313
* @property fireOnce
8317
// this.fireOnce = false;
8320
* fireOnce listeners will fire syncronously unless async
8326
//this.async = false;
8329
* Flag for stopPropagation that is modified during fire()
8330
* 1 means to stop propagation to bubble targets. 2 means
8331
* to also stop additional subscribers on this target.
8335
// this.stopped = 0;
8338
* Flag for preventDefault that is modified during fire().
8339
* if it is not 0, the default behavior for this event
8340
* @property prevented
8343
// this.prevented = 0;
8346
* Specifies the host for this custom event. This is used
8347
* to enable event bubbling
8351
// this.host = null;
8354
* The default function to execute after event listeners
8355
* have fire, but only if the default action was not
8357
* @property defaultFn
8360
// this.defaultFn = null;
8363
* The function to execute if a subscriber calls
8364
* stopPropagation or stopImmediatePropagation
8365
* @property stoppedFn
8368
// this.stoppedFn = null;
8371
* The function to execute if a subscriber calls
8373
* @property preventedFn
8376
// this.preventedFn = null;
8379
* Specifies whether or not this event's default function
8380
* can be cancelled by a subscriber by executing preventDefault()
8381
* on the event facade
8382
* @property preventable
8386
this.preventable = true;
8389
* Specifies whether or not a subscriber can stop the event propagation
8390
* via stopPropagation(), stopImmediatePropagation(), or halt()
8392
* Events can only bubble if emitFacade is true.
8398
this.bubbles = true;
8401
* Supports multiple options for listener signatures in order to
8403
* @property signature
8407
this.signature = YUI3_SIGNATURE;
8410
this.afterCount = 0;
8412
// this.hasSubscribers = false;
8414
// this.hasAfters = false;
8417
* If set to true, the custom event will deliver an EventFacade object
8418
* that is similar to a DOM event object.
8419
* @property emitFacade
8423
// this.emitFacade = false;
8425
this.applyConfig(o, true);
8427
// this.log("Creating " + this.type);
8431
Y.CustomEvent.prototype = {
8432
constructor: Y.CustomEvent,
8435
* Returns the number of subscribers for this event as the sum of the on()
8436
* subscribers and after() subscribers.
8441
hasSubs: function(when) {
8442
var s = this.subCount, a = this.afterCount, sib = this.sibling;
8446
a += sib.afterCount;
8450
return (when == 'after') ? a : s;
8457
* Monitor the event state for the subscribed event. The first parameter
8458
* is what should be monitored, the rest are the normal parameters when
8459
* subscribing to an event.
8461
* @param what {string} what to monitor ('detach', 'attach', 'publish').
8462
* @return {EventHandle} return value from the monitor event subscription.
8464
monitor: function(what) {
8465
this.monitored = true;
8466
var type = this.id + '|' + this.type + '_' + what,
8467
args = Y.Array(arguments, 0, true);
8469
return this.host.on.apply(this.host, args);
8473
* Get all of the subscribers to this event and any sibling event
8475
* @return {Array} first item is the on subscribers, second the after.
8477
getSubs: function() {
8478
var s = Y.merge(this.subscribers), a = Y.merge(this.afters), sib = this.sibling;
8481
Y.mix(s, sib.subscribers);
8482
Y.mix(a, sib.afters);
8489
* Apply configuration properties. Only applies the CONFIG whitelist
8490
* @method applyConfig
8491
* @param o hash of properties to apply.
8492
* @param force {boolean} if true, properties that exist on the event
8493
* will be overwritten.
8495
applyConfig: function(o, force) {
8497
Y.mix(this, o, force, CONFIGS);
8502
* Create the Subscription for subscribing function, context, and bound
8503
* arguments. If this is a fireOnce event, the subscriber is immediately
8507
* @param fn {Function} Subscription callback
8508
* @param [context] {Object} Override `this` in the callback
8509
* @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire()
8510
* @param [when] {String} "after" to slot into after subscribers
8511
* @return {EventHandle}
8514
_on: function(fn, context, args, when) {
8517
this.log('Invalid callback for CE: ' + this.type);
8520
var s = new Y.Subscriber(fn, context, args, when);
8522
if (this.fireOnce && this.fired) {
8524
setTimeout(Y.bind(this._notify, this, s, this.firedWith), 0);
8526
this._notify(s, this.firedWith);
8530
if (when == AFTER) {
8531
this.afters[s.id] = s;
8534
this.subscribers[s.id] = s;
8538
return new Y.EventHandle(this, s);
8543
* Listen for this event
8545
* @param {Function} fn The function to execute.
8546
* @return {EventHandle} Unsubscribe handle.
8547
* @deprecated use on.
8549
subscribe: function(fn, context) {
8550
Y.log('ce.subscribe deprecated, use "on"', 'warn', 'deprecated');
8551
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
8552
return this._on(fn, context, a, true);
8556
* Listen for this event
8558
* @param {Function} fn The function to execute.
8559
* @param {object} context optional execution context.
8560
* @param {mixed} arg* 0..n additional arguments to supply to the subscriber
8561
* when the event fires.
8562
* @return {EventHandle} An object with a detach method to detch the handler(s).
8564
on: function(fn, context) {
8565
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
8567
this.host._monitor('attach', this.type, {
8571
return this._on(fn, context, a, true);
8575
* Listen for this event after the normal subscribers have been notified and
8576
* the default behavior has been applied. If a normal subscriber prevents the
8577
* default behavior, it also prevents after listeners from firing.
8579
* @param {Function} fn The function to execute.
8580
* @param {object} context optional execution context.
8581
* @param {mixed} arg* 0..n additional arguments to supply to the subscriber
8582
* when the event fires.
8583
* @return {EventHandle} handle Unsubscribe handle.
8585
after: function(fn, context) {
8586
var a = (arguments.length > 2) ? Y.Array(arguments, 2, true) : null;
8587
return this._on(fn, context, a, AFTER);
8593
* @param {Function} fn The subscribed function to remove, if not supplied
8594
* all will be removed.
8595
* @param {Object} context The context object passed to subscribe.
8596
* @return {int} returns the number of subscribers unsubscribed.
8598
detach: function(fn, context) {
8599
// unsubscribe handle
8600
if (fn && fn.detach) {
8606
subs = Y.merge(this.subscribers, this.afters);
8609
if (subs.hasOwnProperty(i)) {
8611
if (s && (!fn || fn === s.fn)) {
8623
* @method unsubscribe
8624
* @param {Function} fn The subscribed function to remove, if not supplied
8625
* all will be removed.
8626
* @param {Object} context The context object passed to subscribe.
8627
* @return {int|undefined} returns the number of subscribers unsubscribed.
8628
* @deprecated use detach.
8630
unsubscribe: function() {
8631
return this.detach.apply(this, arguments);
8635
* Notify a single subscriber
8637
* @param {Subscriber} s the subscriber.
8638
* @param {Array} args the arguments array to apply to the listener.
8641
_notify: function(s, args, ef) {
8643
this.log(this.type + '->' + 'sub: ' + s.id);
8647
ret = s.notify(args, this);
8649
if (false === ret || this.stopped > 1) {
8650
this.log(this.type + ' cancelled by subscriber');
8658
* Logger abstraction to centralize the application of the silent flag
8660
* @param {string} msg message to log.
8661
* @param {string} cat log category.
8663
log: function(msg, cat) {
8665
Y.log(this.id + ': ' + msg, cat || 'info', 'event');
8670
* Notifies the subscribers. The callback functions will be executed
8671
* from the context specified when the event was created, and with the
8672
* following parameters:
8674
* <li>The type of event</li>
8675
* <li>All of the arguments fire() was executed with as an array</li>
8676
* <li>The custom object (if any) that was passed into the subscribe()
8680
* @param {Object*} arguments an arbitrary set of parameters to pass to
8682
* @return {boolean} false if one of the subscribers returned false,
8687
if (this.fireOnce && this.fired) {
8688
this.log('fireOnce event: ' + this.type + ' already fired');
8692
var args = Y.Array(arguments, 0, true);
8694
// this doesn't happen if the event isn't published
8695
// this.host._monitor('fire', this.type, args);
8698
this.firedWith = args;
8700
if (this.emitFacade) {
8701
return this.fireComplex(args);
8703
return this.fireSimple(args);
8709
* Set up for notifying subscribers of non-emitFacade events.
8711
* @method fireSimple
8712
* @param args {Array} Arguments passed to fire()
8713
* @return Boolean false if a subscriber returned false
8716
fireSimple: function(args) {
8719
if (this.hasSubs()) {
8720
// this._procSubs(Y.merge(this.subscribers, this.afters), args);
8721
var subs = this.getSubs();
8722
this._procSubs(subs[0], args);
8723
this._procSubs(subs[1], args);
8725
this._broadcast(args);
8726
return this.stopped ? false : true;
8729
// Requires the event-custom-complex module for full funcitonality.
8730
fireComplex: function(args) {
8731
Y.log('Missing event-custom-complex needed to emit a facade for: ' + this.type);
8732
args[0] = args[0] || {};
8733
return this.fireSimple(args);
8737
* Notifies a list of subscribers.
8740
* @param subs {Array} List of subscribers
8741
* @param args {Array} Arguments passed to fire()
8743
* @return Boolean false if a subscriber returns false or stops the event
8744
* propagation via e.stopPropagation(),
8745
* e.stopImmediatePropagation(), or e.halt()
8748
_procSubs: function(subs, args, ef) {
8751
if (subs.hasOwnProperty(i)) {
8754
if (false === this._notify(s, args, ef)) {
8757
if (this.stopped == 2) {
8768
* Notifies the YUI instance if the event is configured with broadcast = 1,
8769
* and both the YUI instance and Y.Global if configured with broadcast = 2.
8771
* @method _broadcast
8772
* @param args {Array} Arguments sent to fire()
8775
_broadcast: function(args) {
8776
if (!this.stopped && this.broadcast) {
8778
var a = Y.Array(args);
8779
a.unshift(this.type);
8781
if (this.host !== Y) {
8785
if (this.broadcast == 2) {
8786
Y.Global.fire.apply(Y.Global, a);
8792
* Removes all listeners
8793
* @method unsubscribeAll
8794
* @return {int} The number of listeners unsubscribed.
8795
* @deprecated use detachAll.
8797
unsubscribeAll: function() {
8798
return this.detachAll.apply(this, arguments);
8802
* Removes all listeners
8804
* @return {int} The number of listeners unsubscribed.
8806
detachAll: function() {
8807
return this.detach();
8811
* Deletes the subscriber from the internal store of on() and after()
8815
* @param subscriber object.
8818
_delete: function(s) {
8820
if (this.subscribers[s.id]) {
8821
delete this.subscribers[s.id];
8824
if (this.afters[s.id]) {
8825
delete this.afters[s.id];
8831
this.host._monitor('detach', this.type, {
8839
// delete s.context;
8845
* Stores the subscriber information to be used when the event fires.
8846
* @param {Function} fn The wrapped function to execute.
8847
* @param {Object} context The value of the keyword 'this' in the listener.
8848
* @param {Array} args* 0..n additional arguments to supply the listener.
8853
Y.Subscriber = function(fn, context, args) {
8856
* The callback that will be execute when the event fires
8857
* This is wrapped by Y.rbind if obj was supplied.
8864
* Optional 'this' keyword for the listener
8868
this.context = context;
8871
* Unique subscriber id
8875
this.id = Y.stamp(this);
8878
* Additional arguments to propagate to the subscriber
8885
* Custom events for a given fire transaction.
8887
* @type {EventTarget}
8889
// this.events = null;
8892
* This listener only reacts to the event once
8895
// this.once = false;
8899
Y.Subscriber.prototype = {
8900
constructor: Y.Subscriber,
8902
_notify: function(c, args, ce) {
8903
if (this.deleted && !this.postponed) {
8904
if (this.postponed) {
8906
delete this.context;
8908
delete this.postponed;
8912
var a = this.args, ret;
8913
switch (ce.signature) {
8915
ret = this.fn.call(c, ce.type, args, c);
8918
ret = this.fn.call(c, args[0] || null, c);
8923
a = (a) ? args.concat(a) : args;
8924
ret = this.fn.apply(c, a);
8926
ret = this.fn.call(c);
8938
* Executes the subscriber.
8940
* @param args {Array} Arguments array for the subscriber.
8941
* @param ce {CustomEvent} The custom event that sent the notification.
8943
notify: function(args, ce) {
8944
var c = this.context,
8948
c = (ce.contextFn) ? ce.contextFn() : ce.context;
8951
// only catch errors if we will not re-throw them.
8952
if (Y.config.throwFail) {
8953
ret = this._notify(c, args, ce);
8956
ret = this._notify(c, args, ce);
8958
Y.error(this + ' failed: ' + e.message, e);
8966
* Returns true if the fn and obj match this objects properties.
8967
* Used by the unsubscribe method to match the right subscriber.
8970
* @param {Function} fn the function to execute.
8971
* @param {Object} context optional 'this' keyword for the listener.
8972
* @return {boolean} true if the supplied arguments match this
8973
* subscriber's signature.
8975
contains: function(fn, context) {
8977
return ((this.fn == fn) && this.context == context);
8979
return (this.fn == fn);
8985
* Return value from all subscribe operations
8986
* @class EventHandle
8988
* @param {CustomEvent} evt the custom event.
8989
* @param {Subscriber} sub the subscriber.
8991
Y.EventHandle = function(evt, sub) {
9000
* The subscriber object
9006
Y.EventHandle.prototype = {
9007
batch: function(f, c) {
9008
f.call(c || this, this);
9009
if (Y.Lang.isArray(this.evt)) {
9010
Y.Array.each(this.evt, function(h) {
9011
h.batch.call(c || h, f);
9017
* Detaches this subscriber
9019
* @return {int} the number of detached listeners
9021
detach: function() {
9022
var evt = this.evt, detached = 0, i;
9024
// Y.log('EventHandle.detach: ' + this.sub, 'info', 'Event');
9025
if (Y.Lang.isArray(evt)) {
9026
for (i = 0; i < evt.length; i++) {
9027
detached += evt[i].detach();
9030
evt._delete(this.sub);
9040
* Monitor the event state for the subscribed event. The first parameter
9041
* is what should be monitored, the rest are the normal parameters when
9042
* subscribing to an event.
9044
* @param what {string} what to monitor ('attach', 'detach', 'publish').
9045
* @return {EventHandle} return value from the monitor event subscription.
9047
monitor: function(what) {
9048
return this.evt.monitor.apply(this.evt, arguments);
9053
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
9055
* @module event-custom
9056
* @submodule event-custom-base
9060
* EventTarget provides the implementation for any object to
9061
* publish, subscribe and fire to custom events, and also
9062
* alows other EventTargets to target the object with events
9063
* sourced from the other object.
9064
* EventTarget is designed to be used with Y.augment to wrap
9065
* EventCustom in an interface that allows events to be listened to
9066
* and fired by name. This makes it possible for implementing code to
9067
* subscribe to an event that either has not been created yet, or will
9068
* not be created at all.
9069
* @class EventTarget
9070
* @param opts a configuration object
9071
* @config emitFacade {boolean} if true, all events will emit event
9072
* facade payloads by default (default false)
9073
* @config prefix {string} the prefix to apply to non-prefixed event names
9074
* @config chain {boolean} if true, on/after/detach return the host to allow
9075
* chaining, otherwise they return an EventHandle (default false)
9079
PREFIX_DELIMITER = ':',
9080
CATEGORY_DELIMITER = '|',
9081
AFTER_PREFIX = '~AFTER~',
9084
_wildType = Y.cached(function(type) {
9085
return type.replace(/(.*)(:)(.*)/, "*$2$3");
9089
* If the instance has a prefix attribute and the
9090
* event type is not prefixed, the instance prefix is
9091
* applied to the supplied type.
9095
_getType = Y.cached(function(type, pre) {
9097
if (!pre || !L.isString(type) || type.indexOf(PREFIX_DELIMITER) > -1) {
9101
return pre + PREFIX_DELIMITER + type;
9105
* Returns an array with the detach key (if provided),
9106
* and the prefixed event name from _getType
9107
* Y.on('detachcategory| menu:click', fn)
9108
* @method _parseType
9111
_parseType = Y.cached(function(type, pre) {
9113
var t = type, detachcategory, after, i;
9115
if (!L.isString(t)) {
9119
i = t.indexOf(AFTER_PREFIX);
9123
t = t.substr(AFTER_PREFIX.length);
9127
i = t.indexOf(CATEGORY_DELIMITER);
9130
detachcategory = t.substr(0, (i));
9137
// detach category, full type with instance prefix, is this an after listener, short type
9138
return [detachcategory, (pre) ? _getType(t, pre) : t, after, t];
9141
ET = function(opts) {
9143
// Y.log('EventTarget constructor executed: ' + this._yuid);
9145
var o = (L.isObject(opts)) ? opts : {};
9147
this._yuievt = this._yuievt || {
9157
chain: ('chain' in o) ? o.chain : Y.config.chain,
9162
context: o.context || this,
9164
emitFacade: o.emitFacade,
9165
fireOnce: o.fireOnce,
9166
queuable: o.queuable,
9167
monitored: o.monitored,
9168
broadcast: o.broadcast,
9169
defaultTargetOnly: o.defaultTargetOnly,
9170
bubbles: ('bubbles' in o) ? o.bubbles : true
9181
* Listen to a custom event hosted by this object one time.
9182
* This is the equivalent to <code>on</code> except the
9183
* listener is immediatelly detached when it is executed.
9185
* @param type {string} The type of the event
9186
* @param fn {Function} The callback
9187
* @param context {object} optional execution context.
9188
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
9189
* @return the event target or a detach handle per 'chain' config
9192
var handle = this.on.apply(this, arguments);
9193
handle.batch(function(hand) {
9195
hand.sub.once = true;
9202
* Listen to a custom event hosted by this object one time.
9203
* This is the equivalent to <code>after</code> except the
9204
* listener is immediatelly detached when it is executed.
9206
* @param type {string} The type of the event
9207
* @param fn {Function} The callback
9208
* @param context {object} optional execution context.
9209
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
9210
* @return the event target or a detach handle per 'chain' config
9212
onceAfter: function() {
9213
var args = YArray(arguments, 0, true);
9214
args[0] = AFTER_PREFIX + args[0];
9216
return this.once.apply(this, args);
9220
* Takes the type parameter passed to 'on' and parses out the
9221
* various pieces that could be included in the type. If the
9222
* event type is passed without a prefix, it will be expanded
9223
* to include the prefix one is supplied or the event target
9224
* is configured with a default prefix.
9226
* @param {string} type the type
9227
* @param {string} [pre=this._yuievt.config.prefix] the prefix
9229
* @return {Array} an array containing:
9230
* * the detach category, if supplied,
9231
* * the prefixed event type,
9232
* * whether or not this is an after listener,
9233
* * the supplied event type
9235
parseType: function(type, pre) {
9236
return _parseType(type, pre || this._yuievt.config.prefix);
9240
* Subscribe to a custom event hosted by this object
9242
* @param type {string} The type of the event
9243
* @param fn {Function} The callback
9244
* @param context {object} optional execution context.
9245
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
9246
* @return the event target or a detach handle per 'chain' config
9248
on: function(type, fn, context) {
9250
var parts = _parseType(type, this._yuievt.config.prefix), f, c, args, ret, ce,
9251
detachcategory, handle, store = Y.Env.evt.handles, after, adapt, shorttype,
9252
Node = Y.Node, n, domevent, isArr;
9254
// full name, args, detachcategory, after
9255
this._monitor('attach', parts[1], {
9261
if (L.isObject(type)) {
9263
if (L.isFunction(type)) {
9264
return Y.Do.before.apply(Y.Do, arguments);
9269
args = YArray(arguments, 0, true);
9272
if (L.isArray(type)) {
9276
after = type._after;
9279
Y.each(type, function(v, k) {
9281
if (L.isObject(v)) {
9282
f = v.fn || ((L.isFunction(v)) ? v : f);
9286
var nv = (after) ? AFTER_PREFIX : '';
9288
args[0] = nv + ((isArr) ? v : k);
9292
ret.push(this.on.apply(this, args));
9296
return (this._yuievt.chain) ? this : new Y.EventHandle(ret);
9300
detachcategory = parts[0];
9302
shorttype = parts[3];
9304
// extra redirection so we catch adaptor events too. take a look at this.
9305
if (Node && Y.instanceOf(this, Node) && (shorttype in Node.DOM_EVENTS)) {
9306
args = YArray(arguments, 0, true);
9307
args.splice(2, 0, Node.getDOMNode(this));
9308
// Y.log("Node detected, redirecting with these args: " + args);
9309
return Y.on.apply(Y, args);
9314
if (Y.instanceOf(this, YUI)) {
9316
adapt = Y.Env.evt.plugins[type];
9317
args = YArray(arguments, 0, true);
9318
args[0] = shorttype;
9323
if (Y.instanceOf(n, Y.NodeList)) {
9324
n = Y.NodeList.getDOMNodes(n);
9325
} else if (Y.instanceOf(n, Node)) {
9326
n = Node.getDOMNode(n);
9329
domevent = (shorttype in Node.DOM_EVENTS);
9331
// Captures both DOM events and event plugins.
9337
// check for the existance of an event adaptor
9339
Y.log('Using adaptor for ' + shorttype + ', ' + n, 'info', 'event');
9340
handle = adapt.on.apply(Y, args);
9341
} else if ((!type) || domevent) {
9342
handle = Y.Event._attach(args);
9348
ce = this._yuievt.events[type] || this.publish(type);
9349
handle = ce._on(fn, context, (arguments.length > 3) ? YArray(arguments, 3, true) : null, (after) ? 'after' : true);
9352
if (detachcategory) {
9353
store[detachcategory] = store[detachcategory] || {};
9354
store[detachcategory][type] = store[detachcategory][type] || [];
9355
store[detachcategory][type].push(handle);
9358
return (this._yuievt.chain) ? this : handle;
9363
* subscribe to an event
9365
* @deprecated use on
9367
subscribe: function() {
9368
Y.log('EventTarget subscribe() is deprecated, use on()', 'warn', 'deprecated');
9369
return this.on.apply(this, arguments);
9373
* Detach one or more listeners the from the specified event
9375
* @param type {string|Object} Either the handle to the subscriber or the
9376
* type of event. If the type
9377
* is not specified, it will attempt to remove
9378
* the listener from all hosted events.
9379
* @param fn {Function} The subscribed function to unsubscribe, if not
9380
* supplied, all subscribers will be removed.
9381
* @param context {Object} The custom object passed to subscribe. This is
9382
* optional, but if supplied will be used to
9383
* disambiguate multiple listeners that are the same
9384
* (e.g., you subscribe many object using a function
9385
* that lives on the prototype)
9386
* @return {EventTarget} the host
9388
detach: function(type, fn, context) {
9389
var evts = this._yuievt.events, i,
9390
Node = Y.Node, isNode = Node && (Y.instanceOf(this, Node));
9392
// detachAll disabled on the Y instance.
9393
if (!type && (this !== Y)) {
9395
if (evts.hasOwnProperty(i)) {
9396
evts[i].detach(fn, context);
9400
Y.Event.purgeElement(Node.getDOMNode(this));
9406
var parts = _parseType(type, this._yuievt.config.prefix),
9407
detachcategory = L.isArray(parts) ? parts[0] : null,
9408
shorttype = (parts) ? parts[3] : null,
9409
adapt, store = Y.Env.evt.handles, detachhost, cat, args,
9412
keyDetacher = function(lcat, ltype, host) {
9413
var handles = lcat[ltype], ce, i;
9415
for (i = handles.length - 1; i >= 0; --i) {
9416
ce = handles[i].evt;
9417
if (ce.host === host || ce.el === host) {
9418
handles[i].detach();
9424
if (detachcategory) {
9426
cat = store[detachcategory];
9428
detachhost = (isNode) ? Y.Node.getDOMNode(this) : this;
9432
keyDetacher(cat, type, detachhost);
9435
if (cat.hasOwnProperty(i)) {
9436
keyDetacher(cat, i, detachhost);
9444
// If this is an event handle, use it to detach
9445
} else if (L.isObject(type) && type.detach) {
9448
// extra redirection so we catch adaptor events too. take a look at this.
9449
} else if (isNode && ((!shorttype) || (shorttype in Node.DOM_EVENTS))) {
9450
args = YArray(arguments, 0, true);
9451
args[2] = Node.getDOMNode(this);
9452
Y.detach.apply(Y, args);
9456
adapt = Y.Env.evt.plugins[shorttype];
9458
// The YUI instance handles DOM events and adaptors
9459
if (Y.instanceOf(this, YUI)) {
9460
args = YArray(arguments, 0, true);
9461
// use the adaptor specific detach code if
9462
if (adapt && adapt.detach) {
9463
adapt.detach.apply(Y, args);
9466
} else if (!type || (!adapt && Node && (type in Node.DOM_EVENTS))) {
9468
Y.Event.detach.apply(Y.Event, args);
9474
ce = evts[parts[1]];
9476
ce.detach(fn, context);
9484
* @method unsubscribe
9485
* @deprecated use detach
9487
unsubscribe: function() {
9488
Y.log('EventTarget unsubscribe() is deprecated, use detach()', 'warn', 'deprecated');
9489
return this.detach.apply(this, arguments);
9493
* Removes all listeners from the specified event. If the event type
9494
* is not specified, all listeners from all hosted custom events will
9497
* @param type {string} The type, or name of the event
9499
detachAll: function(type) {
9500
return this.detach(type);
9504
* Removes all listeners from the specified event. If the event type
9505
* is not specified, all listeners from all hosted custom events will
9507
* @method unsubscribeAll
9508
* @param type {string} The type, or name of the event
9509
* @deprecated use detachAll
9511
unsubscribeAll: function() {
9512
Y.log('EventTarget unsubscribeAll() is deprecated, use detachAll()', 'warn', 'deprecated');
9513
return this.detachAll.apply(this, arguments);
9517
* Creates a new custom event of the specified type. If a custom event
9518
* by that name already exists, it will not be re-created. In either
9519
* case the custom event is returned.
9523
* @param type {string} the type, or name of the event
9524
* @param opts {object} optional config params. Valid properties are:
9528
* 'broadcast': whether or not the YUI instance and YUI global are notified when the event is fired (false)
9531
* 'bubbles': whether or not this event bubbles (true)
9532
* Events can only bubble if emitFacade is true.
9535
* 'context': the default execution context for the listeners (this)
9538
* 'defaultFn': the default function to execute when this event fires if preventDefault was not called
9541
* 'emitFacade': whether or not this event emits a facade (false)
9544
* 'prefix': the prefix for this targets events, e.g., 'menu' in 'menu:click'
9547
* 'fireOnce': if an event is configured to fire once, new subscribers after
9548
* the fire will be notified immediately.
9551
* 'async': fireOnce event listeners will fire synchronously if the event has already
9552
* fired unless async is true.
9555
* 'preventable': whether or not preventDefault() has an effect (true)
9558
* 'preventedFn': a function that is executed when preventDefault is called
9561
* 'queuable': whether or not this event can be queued during bubbling (false)
9564
* 'silent': if silent is true, debug messages are not provided for this event.
9567
* 'stoppedFn': a function that is executed when stopPropagation is called
9571
* 'monitored': specifies whether or not this event should send notifications about
9572
* when the event has been attached, detached, or published.
9575
* 'type': the event type (valid option if not provided as the first parameter to publish)
9579
* @return {CustomEvent} the custom event
9582
publish: function(type, opts) {
9583
var events, ce, ret, defaults,
9584
edata = this._yuievt,
9585
pre = edata.config.prefix;
9587
type = (pre) ? _getType(type, pre) : type;
9589
this._monitor('publish', type, {
9593
if (L.isObject(type)) {
9595
Y.each(type, function(v, k) {
9596
ret[k] = this.publish(k, v || opts);
9602
events = edata.events;
9606
// ce.log("publish applying new config to published event: '"+type+"' exists", 'info', 'event');
9608
ce.applyConfig(opts, true);
9612
defaults = edata.defaults;
9615
ce = new Y.CustomEvent(type,
9616
(opts) ? Y.merge(defaults, opts) : defaults);
9620
// make sure we turn the broadcast flag off if this
9621
// event was published as a result of bubbling
9622
// if (opts instanceof Y.CustomEvent) {
9623
// events[type].broadcast = false;
9626
return events[type];
9630
* This is the entry point for the event monitoring system.
9631
* You can monitor 'attach', 'detach', 'fire', and 'publish'.
9632
* When configured, these events generate an event. click ->
9633
* click_attach, click_detach, click_publish -- these can
9634
* be subscribed to like other events to monitor the event
9635
* system. Inividual published events can have monitoring
9636
* turned on or off (publish can't be turned off before it
9637
* it published) by setting the events 'monitor' config.
9640
* @param what {String} 'attach', 'detach', 'fire', or 'publish'
9641
* @param type {String} Name of the event being monitored
9642
* @param o {Object} Information about the event interaction, such as
9643
* fire() args, subscription category, publish config
9646
_monitor: function(what, type, o) {
9647
var monitorevt, ce = this.getEvent(type);
9648
if ((this._yuievt.config.monitored && (!ce || ce.monitored)) || (ce && ce.monitored)) {
9649
monitorevt = type + '_' + what;
9650
// Y.log('monitoring: ' + monitorevt);
9652
this.fire.call(this, monitorevt, o);
9657
* Fire a custom event by name. The callback functions will be executed
9658
* from the context specified when the event was created, and with the
9659
* following parameters.
9661
* If the custom event object hasn't been created, then the event hasn't
9662
* been published and it has no subscribers. For performance sake, we
9663
* immediate exit in this case. This means the event won't bubble, so
9664
* if the intention is that a bubble target be notified, the event must
9665
* be published on this object first.
9667
* The first argument is the event type, and any additional arguments are
9668
* passed to the listeners as parameters. If the first of these is an
9669
* object literal, and the event is configured to emit an event facade,
9670
* that object is mixed into the event facade and the facade is provided
9671
* in place of the original object.
9674
* @param type {String|Object} The type of the event, or an object that contains
9675
* a 'type' property.
9676
* @param arguments {Object*} an arbitrary set of parameters to pass to
9677
* the handler. If the first of these is an object literal and the event is
9678
* configured to emit an event facade, the event facade will replace that
9679
* parameter after the properties the object literal contains are copied to
9681
* @return {EventTarget} the event host
9684
fire: function(type) {
9686
var typeIncluded = L.isString(type),
9687
t = (typeIncluded) ? type : (type && type.type),
9688
ce, ret, pre = this._yuievt.config.prefix, ce2,
9689
args = (typeIncluded) ? YArray(arguments, 1, true) : arguments;
9691
t = (pre) ? _getType(t, pre) : t;
9693
this._monitor('fire', t, {
9697
ce = this.getEvent(t, true);
9698
ce2 = this.getSibling(t, ce);
9701
ce = this.publish(t);
9704
// this event has not been published or subscribed to
9706
if (this._yuievt.hasTargets) {
9707
return this.bubble({ type: t }, args, this);
9710
// otherwise there is nothing to be done
9714
ret = ce.fire.apply(ce, args);
9717
return (this._yuievt.chain) ? this : ret;
9720
getSibling: function(type, ce) {
9722
// delegate to *:type events if there are subscribers
9723
if (type.indexOf(PREFIX_DELIMITER) > -1) {
9724
type = _wildType(type);
9725
// console.log(type);
9726
ce2 = this.getEvent(type, true);
9728
// console.log("GOT ONE: " + type);
9729
ce2.applyConfig(ce);
9730
ce2.bubbles = false;
9732
// ret = ce2.fire.apply(ce2, a);
9740
* Returns the custom event of the provided type has been created, a
9741
* falsy value otherwise
9743
* @param type {string} the type, or name of the event
9744
* @param prefixed {string} if true, the type is prefixed already
9745
* @return {CustomEvent} the custom event or null
9747
getEvent: function(type, prefixed) {
9750
pre = this._yuievt.config.prefix;
9751
type = (pre) ? _getType(type, pre) : type;
9753
e = this._yuievt.events;
9754
return e[type] || null;
9758
* Subscribe to a custom event hosted by this object. The
9759
* supplied callback will execute after any listeners add
9760
* via the subscribe method, and after the default function,
9761
* if configured for the event, has executed.
9763
* @param type {string} The type of the event
9764
* @param fn {Function} The callback
9765
* @param context {object} optional execution context.
9766
* @param arg* {mixed} 0..n additional arguments to supply to the subscriber
9767
* @return the event target or a detach handle per 'chain' config
9769
after: function(type, fn) {
9771
var a = YArray(arguments, 0, true);
9773
switch (L.type(type)) {
9775
return Y.Do.after.apply(Y.Do, arguments);
9777
// YArray.each(a[0], function(v) {
9778
// v = AFTER_PREFIX + v;
9785
a[0] = AFTER_PREFIX + type;
9788
return this.on.apply(this, a);
9793
* Executes the callback before a DOM event, custom event
9794
* or method. If the first argument is a function, it
9795
* is assumed the target is a method. For DOM and custom
9796
* events, this is an alias for Y.on.
9798
* For DOM and custom events:
9799
* type, callback, context, 0-n arguments
9802
* callback, object (method host), methodName, context, 0-n arguments
9805
* @return detach handle
9807
before: function() {
9808
return this.on.apply(this, arguments);
9815
// make Y an event target
9816
Y.mix(Y, ET.prototype);
9817
ET.call(Y, { bubbles: false });
9819
YUI.Env.globalEvents = YUI.Env.globalEvents || new ET();
9822
* Hosts YUI page level events. This is where events bubble to
9823
* when the broadcast config is set to 2. This property is
9824
* only available if the custom event module is loaded.
9829
Y.Global = YUI.Env.globalEvents;
9831
// @TODO implement a global namespace function on Y.Global?
9834
* <code>YUI</code>'s <code>on</code> method is a unified interface for subscribing to
9835
* most events exposed by YUI. This includes custom events, DOM events, and
9836
* function events. <code>detach</code> is also provided to remove listeners
9837
* serviced by this function.
9839
* The signature that <code>on</code> accepts varies depending on the type
9840
* of event being consumed. Refer to the specific methods that will
9841
* service a specific request for additional information about subscribing
9842
* to that type of event.
9845
* <li>Custom events. These events are defined by various
9846
* modules in the library. This type of event is delegated to
9847
* <code>EventTarget</code>'s <code>on</code> method.
9849
* <li>The type of the event</li>
9850
* <li>The callback to execute</li>
9851
* <li>An optional context object</li>
9852
* <li>0..n additional arguments to supply the callback.</li>
9855
* <code>Y.on('drag:drophit', function() { // start work });</code>
9857
* <li>DOM events. These are moments reported by the browser related
9858
* to browser functionality and user interaction.
9859
* This type of event is delegated to <code>Event</code>'s
9860
* <code>attach</code> method.
9862
* <li>The type of the event</li>
9863
* <li>The callback to execute</li>
9864
* <li>The specification for the Node(s) to attach the listener
9865
* to. This can be a selector, collections, or Node/Element
9867
* <li>An optional context object</li>
9868
* <li>0..n additional arguments to supply the callback.</li>
9871
* <code>Y.on('click', function(e) { // something was clicked }, '#someelement');</code>
9873
* <li>Function events. These events can be used to react before or after a
9874
* function is executed. This type of event is delegated to <code>Event.Do</code>'s
9875
* <code>before</code> method.
9877
* <li>The callback to execute</li>
9878
* <li>The object that has the function that will be listened for.</li>
9879
* <li>The name of the function to listen for.</li>
9880
* <li>An optional context object</li>
9881
* <li>0..n additional arguments to supply the callback.</li>
9883
* Example <code>Y.on(function(arg1, arg2, etc) { // obj.methodname was executed }, obj 'methodname');</code>
9887
* <code>on</code> corresponds to the moment before any default behavior of
9888
* the event. <code>after</code> works the same way, but these listeners
9889
* execute after the event's default behavior. <code>before</code> is an
9890
* alias for <code>on</code>.
9893
* @param type event type (this parameter does not apply for function events)
9894
* @param fn the callback
9895
* @param context optionally change the value of 'this' in the callback
9896
* @param args* 0..n additional arguments to pass to the callback.
9897
* @return the event target or a detach handle per 'chain' config
9902
* Listen for an event one time. Equivalent to <code>on</code>, except that
9903
* the listener is immediately detached when executed.
9906
* @param type event type (this parameter does not apply for function events)
9907
* @param fn the callback
9908
* @param context optionally change the value of 'this' in the callback
9909
* @param args* 0..n additional arguments to pass to the callback.
9910
* @return the event target or a detach handle per 'chain' config
9915
* after() is a unified interface for subscribing to
9916
* most events exposed by YUI. This includes custom events,
9917
* DOM events, and AOP events. This works the same way as
9918
* the on() function, only it operates after any default
9919
* behavior for the event has executed. @see <code>on</code> for more
9922
* @param type event type (this parameter does not apply for function events)
9923
* @param fn the callback
9924
* @param context optionally change the value of 'this' in the callback
9925
* @param args* 0..n additional arguments to pass to the callback.
9926
* @return the event target or a detach handle per 'chain' config
9931
}, '3.4.1' ,{requires:['oop']});
9932
YUI.add('event-custom-complex', function(Y) {
9936
* Adds event facades, preventable default behavior, and bubbling.
9938
* @module event-custom
9939
* @submodule event-custom-complex
9945
CEProto = Y.CustomEvent.prototype,
9946
ETProto = Y.EventTarget.prototype;
9949
* Wraps and protects a custom event for use when emitFacade is set to true.
9950
* Requires the event-custom-complex module
9951
* @class EventFacade
9952
* @param e {Event} the custom event
9953
* @param currentTarget {HTMLElement} the element the listener was attached to
9956
Y.EventFacade = function(e, currentTarget) {
9963
* The arguments passed to fire
9967
this.details = e.details;
9970
* The event type, this can be overridden by the fire() payload
9977
* The real event type
9981
this._type = e.type;
9983
//////////////////////////////////////////////////////
9986
* Node reference for the targeted eventtarget
9990
this.target = e.target;
9993
* Node reference for the element that the listener was attached to.
9994
* @property currentTarget
9997
this.currentTarget = currentTarget;
10000
* Node reference to the relatedTarget
10001
* @property relatedTarget
10004
this.relatedTarget = e.relatedTarget;
10008
Y.extend(Y.EventFacade, Object, {
10011
* Stops the propagation to the next bubble target
10012
* @method stopPropagation
10014
stopPropagation: function() {
10015
this._event.stopPropagation();
10020
* Stops the propagation to the next bubble target and
10021
* prevents any additional listeners from being exectued
10022
* on the current target.
10023
* @method stopImmediatePropagation
10025
stopImmediatePropagation: function() {
10026
this._event.stopImmediatePropagation();
10031
* Prevents the event's default behavior
10032
* @method preventDefault
10034
preventDefault: function() {
10035
this._event.preventDefault();
10036
this.prevented = 1;
10040
* Stops the event propagation and prevents the default
10043
* @param immediate {boolean} if true additional listeners
10044
* on the current target will not be executed
10046
halt: function(immediate) {
10047
this._event.halt(immediate);
10048
this.prevented = 1;
10049
this.stopped = (immediate) ? 2 : 1;
10054
CEProto.fireComplex = function(args) {
10056
var es, ef, q, queue, ce, ret, events, subs, postponed,
10057
self = this, host = self.host || self, next, oldbubble;
10060
// queue this event if the current item in the queue bubbles
10061
if (self.queuable && self.type != self.stack.next.type) {
10062
self.log('queue ' + self.type);
10063
self.stack.queue.push([self, args]);
10068
es = self.stack || {
10069
// id of the first event in the stack
10072
silent: self.silent,
10077
// defaultFnQueue: new Y.Queue(),
10078
afterQueue: new Y.Queue(),
10079
defaultTargetOnly: self.defaultTargetOnly,
10083
subs = self.getSubs();
10085
self.stopped = (self.type !== es.type) ? 0 : es.stopped;
10086
self.prevented = (self.type !== es.type) ? 0 : es.prevented;
10088
self.target = self.target || host;
10090
events = new Y.EventTarget({
10095
self.events = events;
10097
if (self.stoppedFn) {
10098
events.on('stopped', self.stoppedFn);
10101
self.currentTarget = host;
10103
self.details = args.slice(); // original arguments in the details
10105
// self.log("Firing " + self + ", " + "args: " + args);
10106
self.log("Firing " + self.type);
10108
self._facade = null; // kill facade to eliminate stale properties
10110
ef = self._getFacade(args);
10112
if (Y.Lang.isObject(args[0])) {
10120
// self._procSubs(Y.merge(self.subscribers), args, ef);
10121
self._procSubs(subs[0], args, ef);
10124
// bubble if this is hosted in an event target and propagation has not been stopped
10125
if (self.bubbles && host.bubble && !self.stopped) {
10127
oldbubble = es.bubbling;
10129
// self.bubbling = true;
10130
es.bubbling = self.type;
10132
// if (host !== ef.target || es.type != self.type) {
10133
if (es.type != self.type) {
10138
ret = host.bubble(self, args, null, es);
10140
self.stopped = Math.max(self.stopped, es.stopped);
10141
self.prevented = Math.max(self.prevented, es.prevented);
10143
// self.bubbling = false;
10144
es.bubbling = oldbubble;
10148
if (self.prevented) {
10149
if (self.preventedFn) {
10150
self.preventedFn.apply(host, args);
10152
} else if (self.defaultFn &&
10153
((!self.defaultTargetOnly && !es.defaultTargetOnly) ||
10154
host === ef.target)) {
10155
self.defaultFn.apply(host, args);
10158
// broadcast listeners are fired as discreet events on the
10159
// YUI instance and potentially the YUI global.
10160
self._broadcast(args);
10163
if (subs[1] && !self.prevented && self.stopped < 2) {
10164
if (es.id === self.id || self.type != host._yuievt.bubbling) {
10165
self._procSubs(subs[1], args, ef);
10166
while ((next = es.afterQueue.last())) {
10170
postponed = subs[1];
10171
if (es.execDefaultCnt) {
10172
postponed = Y.merge(postponed);
10173
Y.each(postponed, function(s) {
10174
s.postponed = true;
10178
es.afterQueue.add(function() {
10179
self._procSubs(postponed, args, ef);
10184
self.target = null;
10186
if (es.id === self.id) {
10189
while (queue.length) {
10192
// set up stack to allow the next item to be processed
10194
ce.fire.apply(ce, q[1]);
10200
ret = !(self.stopped);
10202
if (self.type != host._yuievt.bubbling) {
10206
self.prevented = 0;
10212
CEProto._getFacade = function() {
10214
var ef = this._facade, o, o2,
10215
args = this.details;
10218
ef = new Y.EventFacade(this, this.currentTarget);
10221
// if the first argument is an object literal, apply the
10222
// properties to the event facade
10223
o = args && args[0];
10225
if (Y.Lang.isObject(o, true)) {
10229
// protect the event facade properties
10230
Y.mix(o2, ef, true, FACADE_KEYS);
10233
Y.mix(ef, o, true);
10236
Y.mix(ef, o2, true, FACADE_KEYS);
10238
// Allow the event type to be faked
10239
// http://yuilibrary.com/projects/yui3/ticket/2528376
10240
ef.type = o.type || ef.type;
10243
// update the details field with the arguments
10244
// ef.type = this.type;
10245
ef.details = this.details;
10247
// use the original target when the event bubbled to this target
10248
ef.target = this.originalTarget || this.target;
10250
ef.currentTarget = this.currentTarget;
10256
return this._facade;
10260
* Stop propagation to bubble targets
10262
* @method stopPropagation
10264
CEProto.stopPropagation = function() {
10267
this.stack.stopped = 1;
10269
this.events.fire('stopped', this);
10273
* Stops propagation to bubble targets, and prevents any remaining
10274
* subscribers on the current target from executing.
10275
* @method stopImmediatePropagation
10277
CEProto.stopImmediatePropagation = function() {
10280
this.stack.stopped = 2;
10282
this.events.fire('stopped', this);
10286
* Prevents the execution of this event's defaultFn
10287
* @method preventDefault
10289
CEProto.preventDefault = function() {
10290
if (this.preventable) {
10291
this.prevented = 1;
10293
this.stack.prevented = 1;
10299
* Stops the event propagation and prevents the default
10302
* @param immediate {boolean} if true additional listeners
10303
* on the current target will not be executed
10305
CEProto.halt = function(immediate) {
10307
this.stopImmediatePropagation();
10309
this.stopPropagation();
10311
this.preventDefault();
10315
* Registers another EventTarget as a bubble target. Bubble order
10316
* is determined by the order registered. Multiple targets can
10319
* Events can only bubble if emitFacade is true.
10321
* Included in the event-custom-complex submodule.
10323
* @method addTarget
10324
* @param o {EventTarget} the target to add
10327
ETProto.addTarget = function(o) {
10328
this._yuievt.targets[Y.stamp(o)] = o;
10329
this._yuievt.hasTargets = true;
10333
* Returns an array of bubble targets for this object.
10334
* @method getTargets
10335
* @return EventTarget[]
10337
ETProto.getTargets = function() {
10338
return Y.Object.values(this._yuievt.targets);
10342
* Removes a bubble target
10343
* @method removeTarget
10344
* @param o {EventTarget} the target to remove
10347
ETProto.removeTarget = function(o) {
10348
delete this._yuievt.targets[Y.stamp(o)];
10352
* Propagate an event. Requires the event-custom-complex module.
10354
* @param evt {CustomEvent} the custom event to propagate
10355
* @return {boolean} the aggregated return value from Event.Custom.fire
10358
ETProto.bubble = function(evt, args, target, es) {
10360
var targs = this._yuievt.targets, ret = true,
10361
t, type = evt && evt.type, ce, i, bc, ce2,
10362
originalTarget = target || (evt && evt.target) || this,
10365
if (!evt || ((!evt.stopped) && targs)) {
10367
// Y.log('Bubbling ' + evt.type);
10369
if (targs.hasOwnProperty(i)) {
10371
ce = t.getEvent(type, true);
10372
ce2 = t.getSibling(type, ce);
10375
ce = t.publish(type);
10378
oldbubble = t._yuievt.bubbling;
10379
t._yuievt.bubbling = type;
10381
// if this event was not published on the bubble target,
10382
// continue propagating the event.
10384
if (t._yuievt.hasTargets) {
10385
t.bubble(evt, args, originalTarget, es);
10391
// set the original target to that the target payload on the
10392
// facade is correct.
10393
ce.target = originalTarget;
10394
ce.originalTarget = originalTarget;
10395
ce.currentTarget = t;
10397
ce.broadcast = false;
10399
// default publish may not have emitFacade true -- that
10400
// shouldn't be what the implementer meant to do
10401
ce.emitFacade = true;
10405
ret = ret && ce.fire.apply(ce, args || evt.details || []);
10407
ce.originalTarget = null;
10410
// stopPropagation() was called
10416
t._yuievt.bubbling = oldbubble;
10424
FACADE = new Y.EventFacade();
10425
FACADE_KEYS = Y.Object.keys(FACADE);
10429
}, '3.4.1' ,{requires:['event-custom-base']});
10430
YUI.add('node-core', function(Y) {
10433
* The Node Utility provides a DOM-like interface for interacting with DOM nodes.
10435
* @submodule node-core
10439
* The Node class provides a wrapper for manipulating DOM Nodes.
10440
* Node properties can be accessed via the set/get methods.
10441
* Use `Y.one()` to retrieve Node instances.
10443
* <strong>NOTE:</strong> Node properties are accessed using
10444
* the <code>set</code> and <code>get</code> methods.
10448
* @param {DOMNode} node the DOM node to be mapped to the Node instance.
10449
* @uses EventTarget
10454
NODE_NAME = 'nodeName',
10455
NODE_TYPE = 'nodeType',
10456
OWNER_DOCUMENT = 'ownerDocument',
10457
TAG_NAME = 'tagName',
10461
_slice = Array.prototype.slice,
10465
Y_Node = function(node) {
10466
if (!this.getDOMNode) { // support optional "new"
10467
return new Y_Node(node);
10470
if (typeof node == 'string') {
10471
node = Y_Node._fromString(node);
10473
return null; // NOTE: return
10477
var uid = (node.nodeType !== 9) ? node.uniqueID : node[UID];
10479
if (uid && Y_Node._instances[uid] && Y_Node._instances[uid]._node !== node) {
10480
node[UID] = null; // unset existing uid to prevent collision (via clone or hack)
10483
uid = uid || Y.stamp(node);
10484
if (!uid) { // stamp failed; likely IE non-HTMLElement
10491
* The underlying DOM node bound to the Y.Node instance
10497
this._stateProxy = node; // when augmented with Attribute
10499
if (this._initPlugins) { // when augmented with Plugin.Host
10500
this._initPlugins();
10504
// used with previous/next/ancestor tests
10505
_wrapFn = function(fn) {
10508
ret = (typeof fn == 'string') ?
10510
return Y.Selector.test(n, fn);
10513
return fn(Y.one(n));
10522
Y_Node.DOM_EVENTS = {};
10524
Y_Node._fromString = function(node) {
10526
if (node.indexOf('doc') === 0) { // doc OR document
10527
node = Y.config.doc;
10528
} else if (node.indexOf('win') === 0) { // win OR window
10529
node = Y.config.win;
10531
node = Y.Selector.query(node, null, true);
10535
return node || null;
10539
* The name of the component
10543
Y_Node.NAME = 'node';
10546
* The pattern used to identify ARIA attributes
10548
Y_Node.re_aria = /^(?:role$|aria-)/;
10550
Y_Node.SHOW_TRANSITION = 'fadeIn';
10551
Y_Node.HIDE_TRANSITION = 'fadeOut';
10554
* A list of Node instances that have been created
10556
* @property _instances
10560
Y_Node._instances = {};
10563
* Retrieves the DOM node bound to a Node instance
10564
* @method getDOMNode
10567
* @param {Y.Node || HTMLNode} node The Node instance or an HTMLNode
10568
* @return {HTMLNode} The DOM node bound to the Node instance. If a DOM node is passed
10569
* as the node argument, it is simply returned.
10571
Y_Node.getDOMNode = function(node) {
10573
return (node.nodeType) ? node : node._node || null;
10579
* Checks Node return values and wraps DOM Nodes as Y.Node instances
10580
* and DOM Collections / Arrays as Y.NodeList instances.
10581
* Other return values just pass thru. If undefined is returned (e.g. no return)
10582
* then the Node instance is returned for chainability.
10586
* @param {any} node The Node instance or an HTMLNode
10587
* @return {Y.Node | Y.NodeList | any} Depends on what is returned from the DOM node.
10589
Y_Node.scrubVal = function(val, node) {
10590
if (val) { // only truthy values are risky
10591
if (typeof val == 'object' || typeof val == 'function') { // safari nodeList === function
10592
if (NODE_TYPE in val || Y_DOM.isWindow(val)) {// node || window
10594
} else if ((val.item && !val._nodes) || // dom collection or Node instance
10595
(val[0] && val[0][NODE_TYPE])) { // array of DOM Nodes
10599
} else if (typeof val === 'undefined') {
10600
val = node; // for chaining
10601
} else if (val === null) {
10602
val = null; // IE: DOM null not the same as null
10609
* Adds methods to the Y.Node prototype, routing through scrubVal.
10610
* @method addMethod
10613
* @param {String} name The name of the method to add
10614
* @param {Function} fn The function that becomes the method
10615
* @param {Object} context An optional context to call the method with
10616
* (defaults to the Node instance)
10617
* @return {any} Depends on what is returned from the DOM node.
10619
Y_Node.addMethod = function(name, fn, context) {
10620
if (name && fn && typeof fn == 'function') {
10621
Y_Node.prototype[name] = function() {
10622
var args = _slice.call(arguments),
10626
if (args[0] && Y.instanceOf(args[0], Y_Node)) {
10627
args[0] = args[0]._node;
10630
if (args[1] && Y.instanceOf(args[1], Y_Node)) {
10631
args[1] = args[1]._node;
10633
args.unshift(node._node);
10635
ret = fn.apply(node, args);
10637
if (ret) { // scrub truthy
10638
ret = Y_Node.scrubVal(ret, node);
10641
(typeof ret != 'undefined') || (ret = node);
10645
Y.log('unable to add method: ' + name, 'warn', 'Node');
10650
* Imports utility methods to be added as Y.Node methods.
10651
* @method importMethod
10654
* @param {Object} host The object that contains the method to import.
10655
* @param {String} name The name of the method to import
10656
* @param {String} altName An optional name to use in place of the host name
10657
* @param {Object} context An optional context to call the method with
10659
Y_Node.importMethod = function(host, name, altName) {
10660
if (typeof name == 'string') {
10661
altName = altName || name;
10662
Y_Node.addMethod(altName, host[name], host);
10664
Y.Array.each(name, function(n) {
10665
Y_Node.importMethod(host, n);
10671
* Retrieves a NodeList based on the given CSS selector.
10674
* @param {string} selector The CSS selector to test against.
10675
* @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
10680
* Returns a single Node instance bound to the node or the
10681
* first element matching the given selector. Returns null if no match found.
10682
* <strong>Note:</strong> For chaining purposes you may want to
10683
* use <code>Y.all</code>, which returns a NodeList when no match is found.
10685
* @param {String | HTMLElement} node a node or Selector
10686
* @return {Y.Node | null} a Node instance or null if no match found.
10691
* Returns a single Node instance bound to the node or the
10692
* first element matching the given selector. Returns null if no match found.
10693
* <strong>Note:</strong> For chaining purposes you may want to
10694
* use <code>Y.all</code>, which returns a NodeList when no match is found.
10697
* @param {String | HTMLElement} node a node or Selector
10698
* @return {Y.Node | null} a Node instance or null if no match found.
10701
Y_Node.one = function(node) {
10702
var instance = null,
10707
if (typeof node == 'string') {
10708
node = Y_Node._fromString(node);
10710
return null; // NOTE: return
10712
} else if (node.getDOMNode) {
10713
return node; // NOTE: return
10716
if (node.nodeType || Y.DOM.isWindow(node)) { // avoid bad input (numbers, boolean, etc)
10717
uid = (node.uniqueID && node.nodeType !== 9) ? node.uniqueID : node._yuid;
10718
instance = Y_Node._instances[uid]; // reuse exising instances
10719
cachedNode = instance ? instance._node : null;
10720
if (!instance || (cachedNode && node !== cachedNode)) { // new Node when nodes don't match
10721
instance = new Y_Node(node);
10722
if (node.nodeType != 11) { // dont cache document fragment
10723
Y_Node._instances[instance[UID]] = instance; // cache node
10733
* The default setter for DOM properties
10734
* Called with instance context (this === the Node instance)
10735
* @method DEFAULT_SETTER
10737
* @param {String} name The attribute/property being set
10738
* @param {any} val The value to be set
10739
* @return {any} The value
10741
Y_Node.DEFAULT_SETTER = function(name, val) {
10742
var node = this._stateProxy,
10745
if (name.indexOf(DOT) > -1) {
10747
name = name.split(DOT);
10748
// only allow when defined on node
10749
Y.Object.setValue(node, name, val);
10750
} else if (typeof node[name] != 'undefined') { // pass thru DOM properties
10758
* The default getter for DOM properties
10759
* Called with instance context (this === the Node instance)
10760
* @method DEFAULT_GETTER
10762
* @param {String} name The attribute/property to look up
10763
* @return {any} The current value
10765
Y_Node.DEFAULT_GETTER = function(name) {
10766
var node = this._stateProxy,
10769
if (name.indexOf && name.indexOf(DOT) > -1) {
10770
val = Y.Object.getValue(node, name.split(DOT));
10771
} else if (typeof node[name] != 'undefined') { // pass thru from DOM
10778
Y.mix(Y_Node.prototype, {
10780
* The method called when outputting Node instances as strings
10782
* @return {String} A string representation of the Node instance
10784
toString: function() {
10785
var str = this[UID] + ': not bound to a node',
10787
attrs, id, className;
10790
attrs = node.attributes;
10791
id = (attrs && attrs.id) ? node.getAttribute('id') : null;
10792
className = (attrs && attrs.className) ? node.getAttribute('className') : null;
10793
str = node[NODE_NAME];
10800
str += '.' + className.replace(' ', '.');
10804
str += ' ' + this[UID];
10810
* Returns an attribute value on the Node instance.
10811
* Unless pre-configured (via `Node.ATTRS`), get hands
10812
* off to the underlying DOM node. Only valid
10813
* attributes/properties for the node will be queried.
10815
* @param {String} attr The attribute
10816
* @return {any} The current value of the attribute
10818
get: function(attr) {
10821
if (this._getAttr) { // use Attribute imple
10822
val = this._getAttr(attr);
10824
val = this._get(attr);
10828
val = Y_Node.scrubVal(val, this);
10829
} else if (val === null) {
10830
val = null; // IE: DOM null is not true null (even though they ===)
10836
* Helper method for get.
10839
* @param {String} attr The attribute
10840
* @return {any} The current value of the attribute
10842
_get: function(attr) {
10843
var attrConfig = Y_Node.ATTRS[attr],
10846
if (attrConfig && attrConfig.getter) {
10847
val = attrConfig.getter.call(this);
10848
} else if (Y_Node.re_aria.test(attr)) {
10849
val = this._node.getAttribute(attr, 2);
10851
val = Y_Node.DEFAULT_GETTER.apply(this, arguments);
10858
* Sets an attribute on the Node instance.
10859
* Unless pre-configured (via Node.ATTRS), set hands
10860
* off to the underlying DOM node. Only valid
10861
* attributes/properties for the node will be set.
10862
* To set custom attributes use setAttribute.
10864
* @param {String} attr The attribute to be set.
10865
* @param {any} val The value to set the attribute to.
10868
set: function(attr, val) {
10869
var attrConfig = Y_Node.ATTRS[attr];
10871
if (this._setAttr) { // use Attribute imple
10872
this._setAttr.apply(this, arguments);
10873
} else { // use setters inline
10874
if (attrConfig && attrConfig.setter) {
10875
attrConfig.setter.call(this, val, attr);
10876
} else if (Y_Node.re_aria.test(attr)) { // special case Aria
10877
this._node.setAttribute(attr, val);
10879
Y_Node.DEFAULT_SETTER.apply(this, arguments);
10887
* Sets multiple attributes.
10889
* @param {Object} attrMap an object of name/value pairs to set
10892
setAttrs: function(attrMap) {
10893
if (this._setAttrs) { // use Attribute imple
10894
this._setAttrs(attrMap);
10895
} else { // use setters inline
10896
Y.Object.each(attrMap, function(v, n) {
10905
* Returns an object containing the values for the requested attributes.
10907
* @param {Array} attrs an array of attributes to get values
10908
* @return {Object} An object with attribute name/value pairs.
10910
getAttrs: function(attrs) {
10912
if (this._getAttrs) { // use Attribute imple
10913
this._getAttrs(attrs);
10914
} else { // use setters inline
10915
Y.Array.each(attrs, function(v, n) {
10916
ret[v] = this.get(v);
10924
* Compares nodes to determine if they match.
10925
* Node instances can be compared to each other and/or HTMLElements.
10926
* @method compareTo
10927
* @param {HTMLElement | Node} refNode The reference node to compare to the node.
10928
* @return {Boolean} True if the nodes match, false if they do not.
10930
compareTo: function(refNode) {
10931
var node = this._node;
10933
if (Y.instanceOf(refNode, Y_Node)) {
10934
refNode = refNode._node;
10936
return node === refNode;
10940
* Determines whether the node is appended to the document.
10942
* @param {Node|HTMLElement} doc optional An optional document to check against.
10943
* Defaults to current document.
10944
* @return {Boolean} Whether or not this node is appended to the document.
10946
inDoc: function(doc) {
10947
var node = this._node;
10948
doc = (doc) ? doc._node || doc : node[OWNER_DOCUMENT];
10949
if (doc.documentElement) {
10950
return Y_DOM.contains(doc.documentElement, node);
10954
getById: function(id) {
10955
var node = this._node,
10956
ret = Y_DOM.byId(id, node[OWNER_DOCUMENT]);
10957
if (ret && Y_DOM.contains(node, ret)) {
10966
* Returns the nearest ancestor that passes the test applied by supplied boolean method.
10968
* @param {String | Function} fn A selector string or boolean method for testing elements.
10969
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
10970
* If a function is used, it receives the current node being tested as the only argument.
10971
* @return {Node} The matching Node instance or null if not found
10973
ancestor: function(fn, testSelf) {
10974
return Y.one(Y_DOM.ancestor(this._node, _wrapFn(fn), testSelf));
10978
* Returns the ancestors that pass the test applied by supplied boolean method.
10979
* @method ancestors
10980
* @param {String | Function} fn A selector string or boolean method for testing elements.
10981
* @param {Boolean} testSelf optional Whether or not to include the element in the scan
10982
* If a function is used, it receives the current node being tested as the only argument.
10983
* @return {NodeList} A NodeList instance containing the matching elements
10985
ancestors: function(fn, testSelf) {
10986
return Y.all(Y_DOM.ancestors(this._node, _wrapFn(fn), testSelf));
10990
* Returns the previous matching sibling.
10991
* Returns the nearest element node sibling if no method provided.
10993
* @param {String | Function} fn A selector or boolean method for testing elements.
10994
* If a function is used, it receives the current node being tested as the only argument.
10995
* @return {Node} Node instance or null if not found
10997
previous: function(fn, all) {
10998
return Y.one(Y_DOM.elementByAxis(this._node, 'previousSibling', _wrapFn(fn), all));
11002
* Returns the next matching sibling.
11003
* Returns the nearest element node sibling if no method provided.
11005
* @param {String | Function} fn A selector or boolean method for testing elements.
11006
* If a function is used, it receives the current node being tested as the only argument.
11007
* @return {Node} Node instance or null if not found
11009
next: function(fn, all) {
11010
return Y.one(Y_DOM.elementByAxis(this._node, 'nextSibling', _wrapFn(fn), all));
11014
* Returns all matching siblings.
11015
* Returns all siblings if no method provided.
11017
* @param {String | Function} fn A selector or boolean method for testing elements.
11018
* If a function is used, it receives the current node being tested as the only argument.
11019
* @return {NodeList} NodeList instance bound to found siblings
11021
siblings: function(fn) {
11022
return Y.all(Y_DOM.siblings(this._node, _wrapFn(fn)));
11026
* Retrieves a Node instance of nodes based on the given CSS selector.
11029
* @param {string} selector The CSS selector to test against.
11030
* @return {Node} A Node instance for the matching HTMLElement.
11032
one: function(selector) {
11033
return Y.one(Y.Selector.query(selector, this._node, true));
11037
* Retrieves a NodeList based on the given CSS selector.
11040
* @param {string} selector The CSS selector to test against.
11041
* @return {NodeList} A NodeList instance for the matching HTMLCollection/Array.
11043
all: function(selector) {
11044
var nodelist = Y.all(Y.Selector.query(selector, this._node));
11045
nodelist._query = selector;
11046
nodelist._queryRoot = this._node;
11050
// TODO: allow fn test
11052
* Test if the supplied node matches the supplied selector.
11055
* @param {string} selector The CSS selector to test against.
11056
* @return {boolean} Whether or not the node matches the selector.
11058
test: function(selector) {
11059
return Y.Selector.test(this._node, selector);
11063
* Removes the node from its parent.
11064
* Shortcut for myNode.get('parentNode').removeChild(myNode);
11066
* @param {Boolean} destroy whether or not to call destroy() on the node
11071
remove: function(destroy) {
11072
var node = this._node;
11074
if (node && node.parentNode) {
11075
node.parentNode.removeChild(node);
11086
* Replace the node with the other node. This is a DOM update only
11087
* and does not change the node bound to the Node instance.
11088
* Shortcut for myNode.get('parentNode').replaceChild(newNode, myNode);
11090
* @param {Y.Node || HTMLNode} newNode Node to be inserted
11094
replace: function(newNode) {
11095
var node = this._node;
11096
if (typeof newNode == 'string') {
11097
newNode = Y_Node.create(newNode);
11099
node.parentNode.replaceChild(Y_Node.getDOMNode(newNode), node);
11104
* @method replaceChild
11106
* @param {String | HTMLElement | Node} node Node to be inserted
11107
* @param {HTMLElement | Node} refNode Node to be replaced
11108
* @return {Node} The replaced node
11110
replaceChild: function(node, refNode) {
11111
if (typeof node == 'string') {
11112
node = Y_DOM.create(node);
11115
return Y.one(this._node.replaceChild(Y_Node.getDOMNode(node), Y_Node.getDOMNode(refNode)));
11119
* Nulls internal node references, removes any plugins and event listeners
11121
* @param {Boolean} recursivePurge (optional) Whether or not to remove listeners from the
11122
* node's subtree (default is false)
11125
destroy: function(recursive) {
11126
var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid',
11129
this.purge(); // TODO: only remove events add via this Node
11131
if (this.unplug) { // may not be a PluginHost
11138
Y.NodeList.each(this.all('*'), function(node) {
11139
instance = Y_Node._instances[node[UID]];
11141
instance.destroy();
11147
this._stateProxy = null;
11149
delete Y_Node._instances[this._yuid];
11153
* Invokes a method on the Node instance
11155
* @param {String} method The name of the method to invoke
11156
* @param {Any} a, b, c, etc. Arguments to invoke the method with.
11157
* @return Whatever the underly method returns.
11158
* DOM Nodes and Collections return values
11159
* are converted to Node/NodeList instances.
11162
invoke: function(method, a, b, c, d, e) {
11163
var node = this._node,
11166
if (a && Y.instanceOf(a, Y_Node)) {
11170
if (b && Y.instanceOf(b, Y_Node)) {
11174
ret = node[method](a, b, c, d, e);
11175
return Y_Node.scrubVal(ret, this);
11180
* @description Swap DOM locations with the given node.
11181
* This does not change which DOM node each Node instance refers to.
11182
* @param {Node} otherNode The node to swap with
11185
swap: Y.config.doc.documentElement.swapNode ?
11186
function(otherNode) {
11187
this._node.swapNode(Y_Node.getDOMNode(otherNode));
11189
function(otherNode) {
11190
otherNode = Y_Node.getDOMNode(otherNode);
11191
var node = this._node,
11192
parent = otherNode.parentNode,
11193
nextSibling = otherNode.nextSibling;
11195
if (nextSibling === node) {
11196
parent.insertBefore(node, otherNode);
11197
} else if (otherNode === node.nextSibling) {
11198
parent.insertBefore(otherNode, node);
11200
node.parentNode.replaceChild(otherNode, node);
11201
Y_DOM.addHTML(parent, node, nextSibling);
11209
* @description Retrieves arbitrary data stored on a Node instance.
11210
* This is not stored with the DOM node.
11211
* @param {string} name Optional name of the data field to retrieve.
11212
* If no name is given, all data is returned.
11213
* @return {any | Object} Whatever is stored at the given field,
11214
* or an object hash of all fields.
11216
getData: function(name) {
11218
this._data = this._data || {};
11219
if (arguments.length) {
11220
ret = this._data[name];
11231
* @description Stores arbitrary data on a Node instance.
11232
* This is not stored with the DOM node.
11233
* @param {string} name The name of the field to set. If no name
11234
* is given, name is treated as the data and overrides any existing data.
11235
* @param {any} val The value to be assigned to the field.
11238
setData: function(name, val) {
11239
this._data = this._data || {};
11240
if (arguments.length > 1) {
11241
this._data[name] = val;
11250
* @method clearData
11251
* @description Clears stored data.
11252
* @param {string} name The name of the field to clear. If no name
11253
* is given, all data is cleared.
11256
clearData: function(name) {
11257
if ('_data' in this) {
11259
delete this._data[name];
11268
hasMethod: function(method) {
11269
var node = this._node;
11270
return !!(node && method in node &&
11271
typeof node[method] != 'unknown' &&
11272
(typeof node[method] == 'function' ||
11273
String(node[method]).indexOf('function') === 1)); // IE reports as object, prepends space
11276
isFragment: function() {
11277
return (this.get('nodeType') === 11);
11281
* Removes and destroys all of the nodes within the node.
11285
empty: function() {
11286
this.get('childNodes').remove().destroy(true);
11291
* Returns the DOM node bound to the Node instance
11292
* @method getDOMNode
11293
* @return {DOMNode}
11295
getDOMNode: function() {
11301
Y.one = Y_Node.one;
11303
* The NodeList module provides support for managing collections of Nodes.
11305
* @submodule node-core
11309
* The NodeList class provides a wrapper for manipulating DOM NodeLists.
11310
* NodeList properties can be accessed via the set/get methods.
11311
* Use Y.all() to retrieve NodeList instances.
11317
var NodeList = function(nodes) {
11319
if (typeof nodes === 'string') { // selector query
11320
this._query = nodes;
11321
nodes = Y.Selector.query(nodes);
11322
} else if (nodes.nodeType || Y_DOM.isWindow(nodes)) { // domNode || window
11324
} else if (Y.instanceOf(nodes, Y.Node)) {
11325
nodes = [nodes._node];
11326
} else if (Y.instanceOf(nodes[0], Y.Node)) { // allow array of Y.Nodes
11327
Y.Array.each(nodes, function(node) {
11329
tmp.push(node._node);
11333
} else { // array of domNodes or domNodeList (no mixed array of Y.Node/domNodes)
11334
nodes = Y.Array(nodes, 0, true);
11338
* The underlying array of DOM nodes bound to the Y.NodeList instance
11342
this._nodes = nodes;
11345
NodeList.NAME = 'NodeList';
11348
* Retrieves the DOM nodes bound to a NodeList instance
11349
* @method getDOMNodes
11352
* @param {Y.NodeList} nodelist The NodeList instance
11353
* @return {Array} The array of DOM nodes bound to the NodeList
11355
NodeList.getDOMNodes = function(nodelist) {
11356
return (nodelist && nodelist._nodes) ? nodelist._nodes : nodelist;
11359
NodeList.each = function(instance, fn, context) {
11360
var nodes = instance._nodes;
11361
if (nodes && nodes.length) {
11362
Y.Array.each(nodes, fn, context || instance);
11364
Y.log('no nodes bound to ' + this, 'warn', 'NodeList');
11368
NodeList.addMethod = function(name, fn, context) {
11370
NodeList.prototype[name] = function() {
11374
Y.Array.each(this._nodes, function(node) {
11375
var UID = (node.uniqueID && node.nodeType !== 9 ) ? 'uniqueID' : '_yuid',
11376
instance = Y.Node._instances[node[UID]],
11381
instance = NodeList._getTempNode(node);
11383
ctx = context || instance;
11384
result = fn.apply(ctx, args);
11385
if (result !== undefined && result !== instance) {
11386
ret[ret.length] = result;
11390
// TODO: remove tmp pointer
11391
return ret.length ? ret : this;
11394
Y.log('unable to add method: ' + name + ' to NodeList', 'warn', 'node');
11398
NodeList.importMethod = function(host, name, altName) {
11399
if (typeof name === 'string') {
11400
altName = altName || name;
11401
NodeList.addMethod(name, host[name]);
11403
Y.Array.each(name, function(n) {
11404
NodeList.importMethod(host, n);
11409
NodeList._getTempNode = function(node) {
11410
var tmp = NodeList._tempNode;
11412
tmp = Y.Node.create('<div></div>');
11413
NodeList._tempNode = tmp;
11417
tmp._stateProxy = node;
11421
Y.mix(NodeList.prototype, {
11423
* Retrieves the Node instance at the given index.
11426
* @param {Number} index The index of the target Node.
11427
* @return {Node} The Node instance at the given index.
11429
item: function(index) {
11430
return Y.one((this._nodes || [])[index]);
11434
* Applies the given function to each Node in the NodeList.
11436
* @param {Function} fn The function to apply. It receives 3 arguments:
11437
* the current node instance, the node's index, and the NodeList instance
11438
* @param {Object} context optional An optional context to apply the function with
11439
* Default context is the current Node instance
11442
each: function(fn, context) {
11443
var instance = this;
11444
Y.Array.each(this._nodes, function(node, index) {
11445
node = Y.one(node);
11446
return fn.call(context || node, node, index, instance);
11451
batch: function(fn, context) {
11452
var nodelist = this;
11454
Y.Array.each(this._nodes, function(node, index) {
11455
var instance = Y.Node._instances[node[UID]];
11457
instance = NodeList._getTempNode(node);
11460
return fn.call(context || instance, instance, index, nodelist);
11466
* Executes the function once for each node until a true value is returned.
11468
* @param {Function} fn The function to apply. It receives 3 arguments:
11469
* the current node instance, the node's index, and the NodeList instance
11470
* @param {Object} context optional An optional context to execute the function from.
11471
* Default context is the current Node instance
11472
* @return {Boolean} Whether or not the function returned true for any node.
11474
some: function(fn, context) {
11475
var instance = this;
11476
return Y.Array.some(this._nodes, function(node, index) {
11477
node = Y.one(node);
11478
context = context || node;
11479
return fn.call(context, node, index, instance);
11484
* Creates a documenFragment from the nodes bound to the NodeList instance
11486
* @return Node a Node instance bound to the documentFragment
11488
toFrag: function() {
11489
return Y.one(Y.DOM._nl2frag(this._nodes));
11493
* Returns the index of the node in the NodeList instance
11494
* or -1 if the node isn't found.
11496
* @param {Y.Node || DOMNode} node the node to search for
11497
* @return {Int} the index of the node value or -1 if not found
11499
indexOf: function(node) {
11500
return Y.Array.indexOf(this._nodes, Y.Node.getDOMNode(node));
11504
* Filters the NodeList instance down to only nodes matching the given selector.
11506
* @param {String} selector The selector to filter against
11507
* @return {NodeList} NodeList containing the updated collection
11510
filter: function(selector) {
11511
return Y.all(Y.Selector.filter(this._nodes, selector));
11516
* Creates a new NodeList containing all nodes at every n indices, where
11517
* remainder n % index equals r.
11518
* (zero-based index).
11520
* @param {Int} n The offset to use (return every nth node)
11521
* @param {Int} r An optional remainder to use with the modulus operation (defaults to zero)
11522
* @return {NodeList} NodeList containing the updated collection
11524
modulus: function(n, r) {
11527
NodeList.each(this, function(node, i) {
11533
return Y.all(nodes);
11537
* Creates a new NodeList containing all nodes at odd indices
11538
* (zero-based index).
11540
* @return {NodeList} NodeList containing the updated collection
11543
return this.modulus(2, 1);
11547
* Creates a new NodeList containing all nodes at even indices
11548
* (zero-based index), including zero.
11550
* @return {NodeList} NodeList containing the updated collection
11553
return this.modulus(2);
11556
destructor: function() {
11560
* Reruns the initial query, when created using a selector query
11564
refresh: function() {
11566
nodes = this._nodes,
11567
query = this._query,
11568
root = this._queryRoot;
11572
if (nodes && nodes[0] && nodes[0].ownerDocument) {
11573
root = nodes[0].ownerDocument;
11577
this._nodes = Y.Selector.query(query, root);
11583
_prepEvtArgs: function(type, fn, context) {
11584
// map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc)
11585
var args = Y.Array(arguments, 0, true);
11587
if (args.length < 2) { // type only (event hash) just add nodes
11588
args[2] = this._nodes;
11590
args.splice(2, 0, this._nodes);
11593
args[3] = context || this; // default to NodeList instance as context
11599
* Applies an event listener to each Node bound to the NodeList.
11601
* @param {String} type The event being listened for
11602
* @param {Function} fn The handler to call when the event fires
11603
* @param {Object} context The context to call the handler with.
11604
* Default is the NodeList instance.
11605
* @param {Object} context The context to call the handler with.
11606
* param {mixed} arg* 0..n additional arguments to supply to the subscriber
11607
* when the event fires.
11608
* @return {Object} Returns an event handle that can later be use to detach().
11611
on: function(type, fn, context) {
11612
return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments));
11616
* Applies an one-time event listener to each Node bound to the NodeList.
11618
* @param {String} type The event being listened for
11619
* @param {Function} fn The handler to call when the event fires
11620
* @param {Object} context The context to call the handler with.
11621
* Default is the NodeList instance.
11622
* @return {Object} Returns an event handle that can later be use to detach().
11625
once: function(type, fn, context) {
11626
return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments));
11630
* Applies an event listener to each Node bound to the NodeList.
11631
* The handler is called only after all on() handlers are called
11632
* and the event is not prevented.
11634
* @param {String} type The event being listened for
11635
* @param {Function} fn The handler to call when the event fires
11636
* @param {Object} context The context to call the handler with.
11637
* Default is the NodeList instance.
11638
* @return {Object} Returns an event handle that can later be use to detach().
11641
after: function(type, fn, context) {
11642
return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments));
11646
* Returns the current number of items in the NodeList.
11648
* @return {Int} The number of items in the NodeList.
11651
return this._nodes.length;
11655
* Determines if the instance is bound to any nodes
11657
* @return {Boolean} Whether or not the NodeList is bound to any nodes
11659
isEmpty: function() {
11660
return this._nodes.length < 1;
11663
toString: function() {
11665
errorMsg = this[UID] + ': not bound to any nodes',
11666
nodes = this._nodes,
11669
if (nodes && nodes[0]) {
11671
str += node[NODE_NAME];
11673
str += '#' + node.id;
11676
if (node.className) {
11677
str += '.' + node.className.replace(' ', '.');
11680
if (nodes.length > 1) {
11681
str += '...[' + nodes.length + ' items]';
11684
return str || errorMsg;
11688
* Returns the DOM node bound to the Node instance
11689
* @method getDOMNodes
11692
getDOMNodes: function() {
11693
return this._nodes;
11697
NodeList.importMethod(Y.Node.prototype, [
11698
/** Called on each Node instance
11700
* @see Node.destroy
11704
/** Called on each Node instance
11710
/** Called on each Node instance
11716
/** Called on each Node instance
11723
// one-off implementation to convert array of Nodes to NodeList
11724
// e.g. Y.all('input').get('parentNode');
11726
/** Called on each Node instance
11730
NodeList.prototype.get = function(attr) {
11732
nodes = this._nodes,
11733
isNodeList = false,
11734
getTemp = NodeList._getTempNode,
11739
instance = Y.Node._instances[nodes[0]._yuid] || getTemp(nodes[0]);
11740
val = instance._get(attr);
11741
if (val && val.nodeType) {
11746
Y.Array.each(nodes, function(node) {
11747
instance = Y.Node._instances[node._yuid];
11750
instance = getTemp(node);
11753
val = instance._get(attr);
11754
if (!isNodeList) { // convert array of Nodes to NodeList
11755
val = Y.Node.scrubVal(val, instance);
11761
return (isNodeList) ? Y.all(ret) : ret;
11764
Y.NodeList = NodeList;
11766
Y.all = function(nodes) {
11767
return new NodeList(nodes);
11770
Y.Node.all = Y.all;
11773
* @submodule node-core
11776
var Y_NodeList = Y.NodeList,
11777
ArrayProto = Array.prototype,
11779
/** Returns a new NodeList combining the given NodeList(s)
11782
* @param {NodeList | Array} valueN Arrays/NodeLists and/or values to
11783
* concatenate to the resulting NodeList
11784
* @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
11787
/** Removes the first last from the NodeList and returns it.
11790
* @return {Node} The last item in the NodeList.
11793
/** Adds the given Node(s) to the end of the NodeList.
11796
* @param {Node | DOMNode} nodes One or more nodes to add to the end of the NodeList.
11799
/** Removes the first item from the NodeList and returns it.
11802
* @return {Node} The first item in the NodeList.
11805
/** Returns a new NodeList comprising the Nodes in the given range.
11808
* @param {Number} begin Zero-based index at which to begin extraction.
11809
As a negative index, start indicates an offset from the end of the sequence. slice(-2) extracts the second-to-last element and the last element in the sequence.
11810
* @param {Number} end Zero-based index at which to end extraction. slice extracts up to but not including end.
11811
slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).
11812
As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.
11813
If end is omitted, slice extracts to the end of the sequence.
11814
* @return {NodeList} A new NodeList comprised of this NodeList joined with the input.
11817
/** Changes the content of the NodeList, adding new elements while removing old elements.
11820
* @param {Number} index Index at which to start changing the array. If negative, will begin that many elements from the end.
11821
* @param {Number} howMany An integer indicating the number of old array elements to remove. If howMany is 0, no elements are removed. In this case, you should specify at least one new element. If no howMany parameter is specified (second syntax above, which is a SpiderMonkey extension), all elements after index are removed.
11822
* {Node | DOMNode| element1, ..., elementN
11823
The elements to add to the array. If you don't specify any elements, splice simply removes elements from the array.
11824
* @return {NodeList} The element(s) removed.
11827
/** Adds the given Node(s) to the beginning of the NodeList.
11830
* @param {Node | DOMNode} nodes One or more nodes to add to the NodeList.
11836
Y.Object.each(ArrayMethods, function(returnNodeList, name) {
11837
Y_NodeList.prototype[name] = function() {
11843
while (typeof (arg = arguments[i++]) != 'undefined') { // use DOM nodes/nodeLists
11844
args.push(arg._node || arg._nodes || arg);
11847
ret = ArrayProto[name].apply(this._nodes, args);
11849
if (returnNodeList) {
11852
ret = Y.Node.scrubVal(ret);
11860
* @submodule node-core
11865
* Passes through to DOM method.
11867
* @method removeChild
11868
* @param {HTMLElement | Node} node Node to be removed
11869
* @return {Node} The removed node
11874
* Passes through to DOM method.
11875
* @method hasChildNodes
11876
* @return {Boolean} Whether or not the node has any childNodes
11881
* Passes through to DOM method.
11882
* @method cloneNode
11883
* @param {Boolean} deep Whether or not to perform a deep clone, which includes
11884
* subtree and attributes
11885
* @return {Node} The clone
11890
* Passes through to DOM method.
11891
* @method hasAttribute
11892
* @param {String} attribute The attribute to test for
11893
* @return {Boolean} Whether or not the attribute is present
11898
* Passes through to DOM method.
11899
* @method removeAttribute
11900
* @param {String} attribute The attribute to be removed
11906
* Passes through to DOM method.
11907
* @method scrollIntoView
11913
* Passes through to DOM method.
11914
* @method getElementsByTagName
11915
* @param {String} tagName The tagName to collect
11916
* @return {NodeList} A NodeList representing the HTMLCollection
11918
'getElementsByTagName',
11921
* Passes through to DOM method.
11928
* Passes through to DOM method.
11935
* Passes through to DOM method.
11936
* Only valid on FORM elements
11943
* Passes through to DOM method.
11944
* Only valid on FORM elements
11951
* Passes through to DOM method.
11958
* Passes through to DOM method.
11959
* Only valid on TABLE elements
11960
* @method createCaption
11965
], function(method) {
11966
Y.log('adding: ' + method, 'info', 'node');
11967
Y.Node.prototype[method] = function(arg1, arg2, arg3) {
11968
var ret = this.invoke(method, arg1, arg2, arg3);
11973
Y.Node.importMethod(Y.DOM, [
11975
* Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
11977
* @param {Node | HTMLElement} needle The possible node or descendent
11978
* @return {Boolean} Whether or not this node is the needle its ancestor
11982
* Allows setting attributes on DOM nodes, normalizing in some cases.
11983
* This passes through to the DOM node, allowing for custom attributes.
11984
* @method setAttribute
11988
* @param {string} name The attribute name
11989
* @param {string} value The value to set
11993
* Allows getting attributes on DOM nodes, normalizing in some cases.
11994
* This passes through to the DOM node, allowing for custom attributes.
11995
* @method getAttribute
11998
* @param {string} name The attribute name
11999
* @return {string} The attribute value
12004
* Wraps the given HTML around the node.
12006
* @param {String} html The markup to wrap around the node.
12013
* Removes the node's parent node.
12020
* Applies a unique ID to the node if none exists
12021
* @method generateID
12022
* @return {String} The existing or generated ID
12027
Y.NodeList.importMethod(Y.Node.prototype, [
12029
* Allows getting attributes on DOM nodes, normalizing in some cases.
12030
* This passes through to the DOM node, allowing for custom attributes.
12031
* @method getAttribute
12034
* @param {string} name The attribute name
12035
* @return {string} The attribute value
12040
* Allows setting attributes on DOM nodes, normalizing in some cases.
12041
* This passes through to the DOM node, allowing for custom attributes.
12042
* @method setAttribute
12046
* @param {string} name The attribute name
12047
* @param {string} value The value to set
12052
* Allows for removing attributes on DOM nodes.
12053
* This passes through to the DOM node, allowing for custom attributes.
12054
* @method removeAttribute
12057
* @param {string} name The attribute to remove
12061
* Removes the parent node from node in the list.
12067
* Wraps the given HTML around each node.
12069
* @param {String} html The markup to wrap around the node.
12075
* Applies a unique ID to each node if none exists
12076
* @method generateID
12077
* @return {String} The existing or generated ID
12083
}, '3.4.1' ,{requires:['dom-core', 'selector']});
12084
YUI.add('node-base', function(Y) {
12088
* @submodule node-base
12093
* Determines whether each node has the given className.
12096
* @param {String} className the class name to search for
12097
* @return {Boolean} Whether or not the element has the specified class
12102
* Adds a class name to each node.
12104
* @param {String} className the class name to add to the node's class attribute
12110
* Removes a class name from each node.
12111
* @method removeClass
12112
* @param {String} className the class name to remove from the node's class attribute
12118
* Replace a class with another class for each node.
12119
* If no oldClassName is present, the newClassName is simply added.
12120
* @method replaceClass
12121
* @param {String} oldClassName the class name to be replaced
12122
* @param {String} newClassName the class name that will be replacing the old class name
12128
* If the className exists on the node it is removed, if it doesn't exist it is added.
12129
* @method toggleClass
12130
* @param {String} className the class name to be toggled
12131
* @param {Boolean} force Option to force adding or removing the class.
12137
Y.Node.importMethod(Y.DOM, methods);
12139
* Determines whether each node has the given className.
12141
* @see Node.hasClass
12143
* @param {String} className the class name to search for
12144
* @return {Array} An array of booleans for each node bound to the NodeList.
12148
* Adds a class name to each node.
12150
* @see Node.addClass
12151
* @param {String} className the class name to add to the node's class attribute
12156
* Removes a class name from each node.
12157
* @method removeClass
12158
* @see Node.removeClass
12159
* @param {String} className the class name to remove from the node's class attribute
12164
* Replace a class with another class for each node.
12165
* If no oldClassName is present, the newClassName is simply added.
12166
* @method replaceClass
12167
* @see Node.replaceClass
12168
* @param {String} oldClassName the class name to be replaced
12169
* @param {String} newClassName the class name that will be replacing the old class name
12174
* If the className exists on the node it is removed, if it doesn't exist it is added.
12175
* @method toggleClass
12176
* @see Node.toggleClass
12177
* @param {String} className the class name to be toggled
12180
Y.NodeList.importMethod(Y.Node.prototype, methods);
12183
* @submodule node-base
12186
var Y_Node = Y.Node,
12190
* Returns a new dom node using the provided markup string.
12193
* @param {String} html The markup used to create the element
12194
* @param {HTMLDocument} doc An optional document context
12195
* @return {Node} A Node instance bound to a DOM node or fragment
12198
Y_Node.create = function(html, doc) {
12199
if (doc && doc._node) {
12202
return Y.one(Y_DOM.create(html, doc));
12205
Y.mix(Y_Node.prototype, {
12207
* Creates a new Node using the provided markup string.
12209
* @param {String} html The markup used to create the element
12210
* @param {HTMLDocument} doc An optional document context
12211
* @return {Node} A Node instance bound to a DOM node or fragment
12213
create: Y_Node.create,
12216
* Inserts the content before the reference node.
12218
* @param {String | Y.Node | HTMLElement | Y.NodeList | HTMLCollection} content The content to insert
12219
* @param {Int | Y.Node | HTMLElement | String} where The position to insert at.
12220
* Possible "where" arguments
12223
* <dd>The Node to insert before</dd>
12224
* <dt>HTMLElement</dt>
12225
* <dd>The element to insert before</dd>
12227
* <dd>The index of the child element to insert before</dd>
12228
* <dt>"replace"</dt>
12229
* <dd>Replaces the existing HTML</dd>
12230
* <dt>"before"</dt>
12231
* <dd>Inserts before the existing HTML</dd>
12232
* <dt>"before"</dt>
12233
* <dd>Inserts content before the node</dd>
12235
* <dd>Inserts content after the node</dd>
12239
insert: function(content, where) {
12240
this._insert(content, where);
12244
_insert: function(content, where) {
12245
var node = this._node,
12248
if (typeof where == 'number') { // allow index
12249
where = this._node.childNodes[where];
12250
} else if (where && where._node) { // Node
12251
where = where._node;
12254
if (content && typeof content != 'string') { // allow Node or NodeList/Array instances
12255
content = content._node || content._nodes || content;
12257
ret = Y_DOM.addHTML(node, content, where);
12263
* Inserts the content as the firstChild of the node.
12265
* @param {String | Y.Node | HTMLElement} content The content to insert
12268
prepend: function(content) {
12269
return this.insert(content, 0);
12273
* Inserts the content as the lastChild of the node.
12275
* @param {String | Y.Node | HTMLElement} content The content to insert
12278
append: function(content) {
12279
return this.insert(content, null);
12283
* @method appendChild
12284
* @param {String | HTMLElement | Node} node Node to be appended
12285
* @return {Node} The appended node
12287
appendChild: function(node) {
12288
return Y_Node.scrubVal(this._insert(node));
12292
* @method insertBefore
12293
* @param {String | HTMLElement | Node} newNode Node to be appended
12294
* @param {HTMLElement | Node} refNode Node to be inserted before
12295
* @return {Node} The inserted node
12297
insertBefore: function(newNode, refNode) {
12298
return Y.Node.scrubVal(this._insert(newNode, refNode));
12302
* Appends the node to the given node.
12304
* @param {Y.Node | HTMLElement} node The node to append to
12307
appendTo: function(node) {
12308
Y.one(node).append(this);
12313
* Replaces the node's current content with the content.
12314
* @method setContent
12315
* @param {String | Y.Node | HTMLElement | Y.NodeList | HTMLCollection} content The content to insert
12318
setContent: function(content) {
12319
this._insert(content, 'replace');
12324
* Returns the node's current content (e.g. innerHTML)
12325
* @method getContent
12326
* @return {String} The current content
12328
getContent: function(content) {
12329
return this.get('innerHTML');
12333
Y.NodeList.importMethod(Y.Node.prototype, [
12335
* Called on each Node instance
12342
/** Called on each Node instance
12349
* Called on each Node instance
12351
* @method appendChild
12352
* @see Node.appendChild
12356
/** Called on each Node instance
12357
* @method insertBefore
12358
* @see Node.insertBefore
12362
/** Called on each Node instance
12364
* @see Node.prepend
12368
/** Called on each Node instance
12369
* @method setContent
12370
* @see Node.setContent
12374
/** Called on each Node instance
12375
* @method getContent
12376
* @see Node.getContent
12382
* @submodule node-base
12385
var Y_Node = Y.Node,
12389
* Static collection of configuration attributes for special handling
12396
* Allows for getting and setting the text of an element.
12397
* Formatting is preserved and special characters are treated literally.
12402
getter: function() {
12403
return Y_DOM.getText(this._node);
12406
setter: function(content) {
12407
Y_DOM.setText(this._node, content);
12413
* Allows for getting and setting the text of an element.
12414
* Formatting is preserved and special characters are treated literally.
12419
getter: function() {
12420
return Y_DOM.getAttribute(this._node, 'for');
12423
setter: function(val) {
12424
Y_DOM.setAttribute(this._node, 'for', val);
12430
getter: function() {
12431
return this._node.getElementsByTagName('option');
12436
* Returns a NodeList instance of all HTMLElement children.
12442
getter: function() {
12443
var node = this._node,
12444
children = node.children,
12445
childNodes, i, len;
12448
childNodes = node.childNodes;
12451
for (i = 0, len = childNodes.length; i < len; ++i) {
12452
if (childNodes[i][TAG_NAME]) {
12453
children[children.length] = childNodes[i];
12457
return Y.all(children);
12462
getter: function() {
12463
return Y_DOM.getValue(this._node);
12466
setter: function(val) {
12467
Y_DOM.setValue(this._node, val);
12473
Y.Node.importMethod(Y.DOM, [
12475
* Allows setting attributes on DOM nodes, normalizing in some cases.
12476
* This passes through to the DOM node, allowing for custom attributes.
12477
* @method setAttribute
12481
* @param {string} name The attribute name
12482
* @param {string} value The value to set
12486
* Allows getting attributes on DOM nodes, normalizing in some cases.
12487
* This passes through to the DOM node, allowing for custom attributes.
12488
* @method getAttribute
12491
* @param {string} name The attribute name
12492
* @return {string} The attribute value
12499
* @submodule node-base
12502
var Y_Node = Y.Node;
12503
var Y_NodeList = Y.NodeList;
12505
* List of events that route to DOM events
12507
* @property DOM_EVENTS
12511
Y_Node.DOM_EVENTS = {
12541
mousemultiwheel: 1,
12546
orientationchange: 1,
12557
// Add custom event adaptors to this list. This will make it so
12558
// that delegate, key, available, contentready, etc all will
12559
// be available through Node.on
12560
Y.mix(Y_Node.DOM_EVENTS, Y.Env.evt.plugins);
12562
Y.augment(Y_Node, Y.EventTarget);
12564
Y.mix(Y_Node.prototype, {
12566
* Removes event listeners from the node and (optionally) its subtree
12568
* @param {Boolean} recurse (optional) Whether or not to remove listeners from the
12570
* @param {String} type (optional) Only remove listeners of the specified type
12574
purge: function(recurse, type) {
12575
Y.Event.purgeElement(this._node, recurse, type);
12581
Y.mix(Y.NodeList.prototype, {
12582
_prepEvtArgs: function(type, fn, context) {
12583
// map to Y.on/after signature (type, fn, nodes, context, arg1, arg2, etc)
12584
var args = Y.Array(arguments, 0, true);
12586
if (args.length < 2) { // type only (event hash) just add nodes
12587
args[2] = this._nodes;
12589
args.splice(2, 0, this._nodes);
12592
args[3] = context || this; // default to NodeList instance as context
12598
* Applies an event listener to each Node bound to the NodeList.
12600
* @param {String} type The event being listened for
12601
* @param {Function} fn The handler to call when the event fires
12602
* @param {Object} context The context to call the handler with.
12603
* Default is the NodeList instance.
12604
* @param {Object} context The context to call the handler with.
12605
* param {mixed} arg* 0..n additional arguments to supply to the subscriber
12606
* when the event fires.
12607
* @return {Object} Returns an event handle that can later be use to detach().
12611
on: function(type, fn, context) {
12612
return Y.on.apply(Y, this._prepEvtArgs.apply(this, arguments));
12616
* Applies an one-time event listener to each Node bound to the NodeList.
12618
* @param {String} type The event being listened for
12619
* @param {Function} fn The handler to call when the event fires
12620
* @param {Object} context The context to call the handler with.
12621
* Default is the NodeList instance.
12622
* @return {Object} Returns an event handle that can later be use to detach().
12625
once: function(type, fn, context) {
12626
return Y.once.apply(Y, this._prepEvtArgs.apply(this, arguments));
12630
* Applies an event listener to each Node bound to the NodeList.
12631
* The handler is called only after all on() handlers are called
12632
* and the event is not prevented.
12634
* @param {String} type The event being listened for
12635
* @param {Function} fn The handler to call when the event fires
12636
* @param {Object} context The context to call the handler with.
12637
* Default is the NodeList instance.
12638
* @return {Object} Returns an event handle that can later be use to detach().
12641
after: function(type, fn, context) {
12642
return Y.after.apply(Y, this._prepEvtArgs.apply(this, arguments));
12646
* Applies an one-time event listener to each Node bound to the NodeList
12647
* that will be called only after all on() handlers are called and the
12648
* event is not prevented.
12650
* @method onceAfter
12651
* @param {String} type The event being listened for
12652
* @param {Function} fn The handler to call when the event fires
12653
* @param {Object} context The context to call the handler with.
12654
* Default is the NodeList instance.
12655
* @return {Object} Returns an event handle that can later be use to detach().
12658
onceAfter: function(type, fn, context) {
12659
return Y.onceAfter.apply(Y, this._prepEvtArgs.apply(this, arguments));
12663
Y_NodeList.importMethod(Y.Node.prototype, [
12665
* Called on each Node instance
12671
/** Called on each Node instance
12672
* @method detachAll
12673
* @see Node.detachAll
12677
Y.mix(Y.Node.ATTRS, {
12679
setter: function(h) {
12680
Y.DOM.setHeight(this._node, h);
12684
getter: function() {
12685
return this._node.offsetHeight;
12690
setter: function(w) {
12691
Y.DOM.setWidth(this._node, w);
12695
getter: function() {
12696
return this._node.offsetWidth;
12701
Y.mix(Y.Node.prototype, {
12702
sizeTo: function(w, h) {
12704
if (arguments.length < 2) {
12706
w = node.get('offsetWidth');
12707
h = node.get('offsetHeight');
12718
* @submodule node-base
12721
var Y_Node = Y.Node;
12723
Y.mix(Y_Node.prototype, {
12725
* Makes the node visible.
12726
* If the "transition" module is loaded, show optionally
12727
* animates the showing of the node using either the default
12728
* transition effect ('fadeIn'), or the given named effect.
12731
* @param {String} name A named Transition effect to use as the show effect.
12732
* @param {Object} config Options to use with the transition.
12733
* @param {Function} callback An optional function to run after the transition completes.
12736
show: function(callback) {
12737
callback = arguments[arguments.length - 1];
12738
this.toggleView(true, callback);
12743
* The implementation for showing nodes.
12744
* Default is to toggle the style.display property.
12749
_show: function() {
12750
this.setStyle('display', '');
12754
_isHidden: function() {
12755
return Y.DOM.getStyle(this._node, 'display') === 'none';
12758
toggleView: function(on, callback) {
12759
this._toggleView.apply(this, arguments);
12762
_toggleView: function(on, callback) {
12763
callback = arguments[arguments.length - 1];
12765
// base on current state if not forcing
12766
if (typeof on != 'boolean') {
12767
on = (this._isHidden()) ? 1 : 0;
12776
if (typeof callback == 'function') {
12777
callback.call(this);
12785
* If the "transition" module is loaded, hide optionally
12786
* animates the hiding of the node using either the default
12787
* transition effect ('fadeOut'), or the given named effect.
12789
* @param {String} name A named Transition effect to use as the show effect.
12790
* @param {Object} config Options to use with the transition.
12791
* @param {Function} callback An optional function to run after the transition completes.
12794
hide: function(callback) {
12795
callback = arguments[arguments.length - 1];
12796
this.toggleView(false, callback);
12801
* The implementation for hiding nodes.
12802
* Default is to toggle the style.display property.
12807
_hide: function() {
12808
this.setStyle('display', 'none');
12812
Y.NodeList.importMethod(Y.Node.prototype, [
12814
* Makes each node visible.
12815
* If the "transition" module is loaded, show optionally
12816
* animates the showing of the node using either the default
12817
* transition effect ('fadeIn'), or the given named effect.
12819
* @param {String} name A named Transition effect to use as the show effect.
12820
* @param {Object} config Options to use with the transition.
12821
* @param {Function} callback An optional function to run after the transition completes.
12829
* If the "transition" module is loaded, hide optionally
12830
* animates the hiding of the node using either the default
12831
* transition effect ('fadeOut'), or the given named effect.
12833
* @param {String} name A named Transition effect to use as the show effect.
12834
* @param {Object} config Options to use with the transition.
12835
* @param {Function} callback An optional function to run after the transition completes.
12843
if (!Y.config.doc.documentElement.hasAttribute) { // IE < 8
12844
Y.Node.prototype.hasAttribute = function(attr) {
12845
if (attr === 'value') {
12846
if (this.get('value') !== "") { // IE < 8 fails to populate specified when set in HTML
12850
return !!(this._node.attributes[attr] &&
12851
this._node.attributes[attr].specified);
12855
// IE throws an error when calling focus() on an element that's invisible, not
12856
// displayed, or disabled.
12857
Y.Node.prototype.focus = function () {
12859
this._node.focus();
12861
Y.log('error focusing node: ' + e.toString(), 'error', 'node');
12867
// IE throws error when setting input.type = 'hidden',
12868
// input.setAttribute('type', 'hidden') and input.attributes.type.value = 'hidden'
12869
Y.Node.ATTRS.type = {
12870
setter: function(val) {
12871
if (val === 'hidden') {
12873
this._node.type = 'hidden';
12875
this.setStyle('display', 'none');
12876
this._inputType = 'hidden';
12879
try { // IE errors when changing the type from "hidden'
12880
this._node.type = val;
12882
Y.log('error setting type: ' + val, 'info', 'node');
12888
getter: function() {
12889
return this._inputType || this._node.type;
12892
_bypassProxy: true // don't update DOM when using with Attribute
12895
if (Y.config.doc.createElement('form').elements.nodeType) {
12896
// IE: elements collection is also FORM node which trips up scrubVal.
12897
Y.Node.ATTRS.elements = {
12898
getter: function() {
12899
return this.all('input, textarea, button, select');
12906
}, '3.4.1' ,{requires:['dom-base', 'node-core', 'event-base']});
12908
var GLOBAL_ENV = YUI.Env;
12910
if (!GLOBAL_ENV._ready) {
12911
GLOBAL_ENV._ready = function() {
12912
GLOBAL_ENV.DOMReady = true;
12913
GLOBAL_ENV.remove(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
12916
GLOBAL_ENV.add(YUI.config.doc, 'DOMContentLoaded', GLOBAL_ENV._ready);
12919
YUI.add('event-base', function(Y) {
12922
* DOM event listener abstraction layer
12924
* @submodule event-base
12928
* The domready event fires at the moment the browser's DOM is
12929
* usable. In most cases, this is before images are fully
12930
* downloaded, allowing you to provide a more responsive user
12933
* In YUI 3, domready subscribers will be notified immediately if
12934
* that moment has already passed when the subscription is created.
12936
* One exception is if the yui.js file is dynamically injected into
12937
* the page. If this is done, you must tell the YUI instance that
12938
* you did this in order for DOMReady (and window load events) to
12939
* fire normally. That configuration option is 'injected' -- set
12940
* it to true if the yui.js script is not included inline.
12942
* This method is part of the 'event-ready' module, which is a
12943
* submodule of 'event'.
12948
Y.publish('domready', {
12953
if (YUI.Env.DOMReady) {
12954
Y.fire('domready');
12956
Y.Do.before(function() { Y.fire('domready'); }, YUI.Env, '_ready');
12960
* Custom event engine, DOM event listener abstraction layer, synthetic DOM
12963
* @submodule event-base
12967
* Wraps a DOM event, properties requiring browser abstraction are
12968
* fixed here. Provids a security layer when required.
12969
* @class DOMEventFacade
12970
* @param ev {Event} the DOM event
12971
* @param currentTarget {HTMLElement} the element the listener was attached to
12972
* @param wrapper {Event.Custom} the custom event wrapper for this DOM event
12980
* webkit key remapping required for Safari < 3.1
12981
* @property webkitKeymap
12988
63235: 39, // right
12989
63276: 33, // page up
12990
63277: 34, // page down
12991
25: 9, // SHIFT-TAB (Safari provides a different key code in
12992
// this case, even though the shiftKey modifier is set)
12993
63272: 46, // delete
12999
* Returns a wrapped node. Intended to be used on event targets,
13000
* so it will return the node's parent if the target is a text
13003
* If accessing a property of the node throws an error, this is
13004
* probably the anonymous div wrapper Gecko adds inside text
13005
* nodes. This likely will only occur when attempting to access
13006
* the relatedTarget. In this case, we now return null because
13007
* the anonymous div is completely useless and we do not know
13008
* what the related target was because we can't even get to
13009
* the element's parent node.
13014
resolve = function(n) {
13019
if (n && 3 == n.nodeType) {
13029
DOMEventFacade = function(ev, currentTarget, wrapper) {
13031
this._currentTarget = currentTarget;
13032
this._wrapper = wrapper || EMPTY;
13034
// if not lazy init
13038
Y.extend(DOMEventFacade, Object, {
13042
var e = this._event,
13043
overrides = this._wrapper.overrides,
13047
currentTarget = this._currentTarget;
13049
this.altKey = e.altKey;
13050
this.ctrlKey = e.ctrlKey;
13051
this.metaKey = e.metaKey;
13052
this.shiftKey = e.shiftKey;
13053
this.type = (overrides && overrides.type) || e.type;
13054
this.clientX = e.clientX;
13055
this.clientY = e.clientY;
13060
c = e.keyCode || e.charCode;
13062
if (ua.webkit && (c in webkitKeymap)) {
13063
c = webkitKeymap[c];
13068
this.which = e.which || e.charCode || c;
13069
// this.button = e.button;
13070
this.button = this.which;
13072
this.target = resolve(e.target);
13073
this.currentTarget = resolve(currentTarget);
13074
this.relatedTarget = resolve(e.relatedTarget);
13076
if (e.type == "mousewheel" || e.type == "DOMMouseScroll") {
13077
this.wheelDelta = (e.detail) ? (e.detail * -1) : Math.round(e.wheelDelta / 80) || ((e.wheelDelta < 0) ? -1 : 1);
13081
this._touch(e, currentTarget, this._wrapper);
13085
stopPropagation: function() {
13086
this._event.stopPropagation();
13087
this._wrapper.stopped = 1;
13091
stopImmediatePropagation: function() {
13092
var e = this._event;
13093
if (e.stopImmediatePropagation) {
13094
e.stopImmediatePropagation();
13096
this.stopPropagation();
13098
this._wrapper.stopped = 2;
13102
preventDefault: function(returnValue) {
13103
var e = this._event;
13104
e.preventDefault();
13105
e.returnValue = returnValue || false;
13106
this._wrapper.prevented = 1;
13107
this.prevented = 1;
13110
halt: function(immediate) {
13112
this.stopImmediatePropagation();
13114
this.stopPropagation();
13117
this.preventDefault();
13122
DOMEventFacade.resolve = resolve;
13123
Y.DOM2EventFacade = DOMEventFacade;
13124
Y.DOMEventFacade = DOMEventFacade;
13132
* The X location of the event on the page (including scroll)
13138
* The Y location of the event on the page (including scroll)
13144
* The keyCode for key events. Uses charCode if keyCode is not available
13145
* @property keyCode
13150
* The charCode for key events. Same as keyCode
13151
* @property charCode
13156
* The button that was pushed.
13162
* The button that was pushed. Same as button.
13168
* Node reference for the targeted element
13174
* Node reference for the element that the listener was attached to.
13175
* @propery currentTarget
13180
* Node reference to the relatedTarget
13181
* @propery relatedTarget
13186
* Number representing the direction and velocity of the movement of the mousewheel.
13187
* Negative is down, the higher the number, the faster. Applies to the mousewheel event.
13188
* @property wheelDelta
13193
* Stops the propagation to the next bubble target
13194
* @method stopPropagation
13198
* Stops the propagation to the next bubble target and
13199
* prevents any additional listeners from being exectued
13200
* on the current target.
13201
* @method stopImmediatePropagation
13205
* Prevents the event's default behavior
13206
* @method preventDefault
13207
* @param returnValue {string} sets the returnValue of the event to this value
13208
* (rather than the default false value). This can be used to add a customized
13209
* confirmation query to the beforeunload event).
13213
* Stops the event propagation and prevents the default
13216
* @param immediate {boolean} if true additional listeners
13217
* on the current target will not be executed
13221
* DOM event listener abstraction layer
13223
* @submodule event-base
13227
* The event utility provides functions to add and remove event listeners,
13228
* event cleansing. It also tries to automatically remove listeners it
13229
* registers during the unload event.
13235
Y.Env.evt.dom_wrappers = {};
13236
Y.Env.evt.dom_map = {};
13238
var _eventenv = Y.Env.evt,
13242
remove = YUI.Env.remove,
13244
onLoad = function() {
13245
YUI.Env.windowLoaded = true;
13247
remove(win, "load", onLoad);
13250
onUnload = function() {
13254
EVENT_READY = 'domready',
13256
COMPAT_ARG = '~yui|2|compat~',
13258
shouldIterate = function(o) {
13260
return (o && typeof o !== "string" && Y.Lang.isNumber(o.length) &&
13261
!o.tagName && !o.alert);
13263
Y.log("collection check failure", "warn", "event");
13269
// aliases to support DOM event subscription clean up when the last
13270
// subscriber is detached. deleteAndClean overrides the DOM event's wrapper
13271
// CustomEvent _delete method.
13272
_ceProtoDelete = Y.CustomEvent.prototype._delete,
13273
_deleteAndClean = function(s) {
13274
var ret = _ceProtoDelete.apply(this, arguments);
13276
if (!this.subCount && !this.afterCount) {
13277
Y.Event._clean(this);
13283
Event = function() {
13286
* True after the onload event has fired
13287
* @property _loadComplete
13292
var _loadComplete = false,
13295
* The number of times to poll after window.onload. This number is
13296
* increased if additional late-bound handlers are requested after
13298
* @property _retryCount
13305
* onAvailable listeners
13313
* Custom event wrappers for DOM events. Key is
13314
* 'event:' + Element uid stamp + event type
13315
* @property _wrappers
13316
* @type Y.Event.Custom
13320
_wrappers = _eventenv.dom_wrappers,
13322
_windowLoadKey = null,
13325
* Custom event wrapper map DOM events. Key is
13326
* Element uid stamp. Each item is a hash of custom event
13327
* wrappers as provided in the _wrappers collection. This
13328
* provides the infrastructure for getListeners.
13329
* @property _el_events
13333
_el_events = _eventenv.dom_map;
13338
* The number of times we should look for elements that are not
13339
* in the DOM at the time the event is requested after the document
13340
* has been loaded. The default is 1000@amp;40 ms, so it will poll
13341
* for 40 seconds or until all outstanding handlers are bound
13342
* (whichever comes first).
13343
* @property POLL_RETRYS
13351
* The poll interval in milliseconds
13352
* @property POLL_INTERVAL
13360
* addListener/removeListener can throw errors in unexpected scenarios.
13361
* These errors are suppressed, the method returns false, and this property
13363
* @property lastError
13372
* @property _interval
13379
* document readystate poll handle
13387
* True when the document is initially usable
13388
* @property DOMReady
13395
* @method startInterval
13399
startInterval: function() {
13400
if (!Event._interval) {
13401
Event._interval = setInterval(Event._poll, Event.POLL_INTERVAL);
13406
* Executes the supplied callback when the item with the supplied
13407
* id is found. This is meant to be used to execute behavior as
13408
* soon as possible as the page loads. If you use this after the
13409
* initial page load it will poll for a fixed time for the element.
13410
* The number of times it will poll and the frequency are
13411
* configurable. By default it will poll for 10 seconds.
13413
* <p>The callback is executed with a single parameter:
13414
* the custom object parameter, if provided.</p>
13416
* @method onAvailable
13418
* @param {string||string[]} id the id of the element, or an array
13419
* of ids to look for.
13420
* @param {function} fn what to execute when the element is found.
13421
* @param {object} p_obj an optional object to be passed back as
13422
* a parameter to fn.
13423
* @param {boolean|object} p_override If set to true, fn will execute
13424
* in the context of p_obj, if set to an object it
13425
* will execute in the context of that object
13426
* @param checkContent {boolean} check child node readiness (onContentReady)
13428
* @deprecated Use Y.on("available")
13430
// @TODO fix arguments
13431
onAvailable: function(id, fn, p_obj, p_override, checkContent, compat) {
13433
var a = Y.Array(id), i, availHandle;
13435
// Y.log('onAvailable registered for: ' + id);
13437
for (i=0; i<a.length; i=i+1) {
13442
override: p_override,
13443
checkReady: checkContent,
13447
_retryCount = this.POLL_RETRYS;
13449
// We want the first test to be immediate, but async
13450
setTimeout(Event._poll, 0);
13452
availHandle = new Y.EventHandle({
13454
_delete: function() {
13455
// set by the event system for lazy DOM listeners
13456
if (availHandle.handle) {
13457
availHandle.handle.detach();
13463
// otherwise try to remove the onAvailable listener(s)
13464
for (i = 0; i < a.length; i++) {
13465
for (j = 0; j < _avail.length; j++) {
13466
if (a[i] === _avail[j].id) {
13467
_avail.splice(j, 1);
13475
return availHandle;
13479
* Works the same way as onAvailable, but additionally checks the
13480
* state of sibling elements to determine if the content of the
13481
* available element is safe to modify.
13483
* <p>The callback is executed with a single parameter:
13484
* the custom object parameter, if provided.</p>
13486
* @method onContentReady
13488
* @param {string} id the id of the element to look for.
13489
* @param {function} fn what to execute when the element is ready.
13490
* @param {object} obj an optional object to be passed back as
13491
* a parameter to fn.
13492
* @param {boolean|object} override If set to true, fn will execute
13493
* in the context of p_obj. If an object, fn will
13494
* exectute in the context of that object
13497
* @deprecated Use Y.on("contentready")
13499
// @TODO fix arguments
13500
onContentReady: function(id, fn, obj, override, compat) {
13501
return Event.onAvailable(id, fn, obj, override, true, compat);
13505
* Adds an event listener
13509
* @param {String} type The type of event to append
13510
* @param {Function} fn The method the event invokes
13511
* @param {String|HTMLElement|Array|NodeList} el An id, an element
13512
* reference, or a collection of ids and/or elements to assign the
13514
* @param {Object} context optional context object
13515
* @param {Boolean|object} args 0..n arguments to pass to the callback
13516
* @return {EventHandle} an object to that can be used to detach the listener
13521
attach: function(type, fn, el, context) {
13522
return Event._attach(Y.Array(arguments, 0, true));
13525
_createWrapper: function (el, type, capture, compat, facade) {
13529
key = 'event:' + ek + type;
13531
if (false === facade) {
13539
cewrapper = _wrappers[key];
13543
// create CE wrapper
13544
cewrapper = Y.publish(key, {
13547
contextFn: function() {
13549
return cewrapper.el;
13551
cewrapper.nodeRef = cewrapper.nodeRef || Y.one(cewrapper.el);
13552
return cewrapper.nodeRef;
13557
cewrapper.overrides = {};
13559
// for later removeListener calls
13561
cewrapper.key = key;
13562
cewrapper.domkey = ek;
13563
cewrapper.type = type;
13564
cewrapper.fn = function(e) {
13565
cewrapper.fire(Event.getEvent(e, el, (compat || (false === facade))));
13567
cewrapper.capture = capture;
13569
if (el == win && type == "load") {
13570
// window load happens once
13571
cewrapper.fireOnce = true;
13572
_windowLoadKey = key;
13574
cewrapper._delete = _deleteAndClean;
13576
_wrappers[key] = cewrapper;
13577
_el_events[ek] = _el_events[ek] || {};
13578
_el_events[ek][key] = cewrapper;
13580
add(el, type, cewrapper.fn, capture);
13587
_attach: function(args, conf) {
13590
handles, oEl, cewrapper, context,
13591
fireNow = false, ret,
13594
el = args[2] || win,
13595
facade = conf && conf.facade,
13596
capture = conf && conf.capture,
13597
overrides = conf && conf.overrides;
13599
if (args[args.length-1] === COMPAT_ARG) {
13603
if (!fn || !fn.call) {
13604
// throw new TypeError(type + " attach call failed, callback undefined");
13605
Y.log(type + " attach call failed, invalid callback", "error", "event");
13609
// The el argument can be an array of elements or element ids.
13610
if (shouldIterate(el)) {
13614
Y.each(el, function(v, k) {
13616
handles.push(Event._attach(args.slice(), conf));
13619
// return (handles.length === 1) ? handles[0] : handles;
13620
return new Y.EventHandle(handles);
13622
// If the el argument is a string, we assume it is
13623
// actually the id of the element. If the page is loaded
13624
// we convert el to the actual element, otherwise we
13625
// defer attaching the event until the element is
13627
} else if (Y.Lang.isString(el)) {
13629
// oEl = (compat) ? Y.DOM.byId(el) : Y.Selector.query(el);
13632
oEl = Y.DOM.byId(el);
13635
oEl = Y.Selector.query(el);
13637
switch (oEl.length) {
13646
return Event._attach(args, conf);
13654
// Not found = defer adding the event until the element is available
13657
// Y.log(el + ' not found');
13658
ret = Event.onAvailable(el, function() {
13659
// Y.log('lazy attach: ' + args);
13661
ret.handle = Event._attach(args, conf);
13663
}, Event, true, false, compat);
13670
// Element should be an html element or node
13672
Y.log("unable to attach event " + type, "warn", "event");
13676
if (Y.Node && Y.instanceOf(el, Y.Node)) {
13677
el = Y.Node.getDOMNode(el);
13680
cewrapper = Event._createWrapper(el, type, capture, compat, facade);
13682
Y.mix(cewrapper.overrides, overrides);
13685
if (el == win && type == "load") {
13687
// if the load is complete, fire immediately.
13688
// all subscribers, including the current one
13689
// will be notified.
13690
if (YUI.Env.windowLoaded) {
13701
// set context to the Node if not specified
13702
// ret = cewrapper.on.apply(cewrapper, trimmedArgs);
13703
ret = cewrapper._on(fn, context, (args.length > 4) ? args.slice(4) : null);
13714
* Removes an event listener. Supports the signature the event was bound
13715
* with, but the preferred way to remove listeners is using the handle
13716
* that is returned when using Y.on
13720
* @param {String} type the type of event to remove.
13721
* @param {Function} fn the method the event invokes. If fn is
13722
* undefined, then all event handlers for the type of event are
13724
* @param {String|HTMLElement|Array|NodeList|EventHandle} el An
13725
* event handle, an id, an element reference, or a collection
13726
* of ids and/or elements to remove the listener from.
13727
* @return {boolean} true if the unbind was successful, false otherwise.
13730
detach: function(type, fn, el, obj) {
13732
var args=Y.Array(arguments, 0, true), compat, l, ok, i,
13735
if (args[args.length-1] === COMPAT_ARG) {
13740
if (type && type.detach) {
13741
return type.detach();
13744
// The el argument can be a string
13745
if (typeof el == "string") {
13747
// el = (compat) ? Y.DOM.byId(el) : Y.all(el);
13749
el = Y.DOM.byId(el);
13751
el = Y.Selector.query(el);
13755
} else if (l == 1) {
13759
// return Event.detach.apply(Event, args);
13768
return el.detach.apply(el, args);
13769
// The el argument can be an array of elements or element ids.
13770
} else if (shouldIterate(el)) {
13772
for (i=0, l=el.length; i<l; ++i) {
13774
ok = ( Y.Event.detach.apply(Y.Event, args) && ok );
13780
if (!type || !fn || !fn.call) {
13781
return Event.purgeElement(el, false, type);
13784
id = 'event:' + Y.stamp(el) + type;
13785
ce = _wrappers[id];
13788
return ce.detach(fn);
13796
* Finds the event in the window object, the caller's arguments, or
13797
* in the arguments of another method in the callstack. This is
13798
* executed automatically for events registered through the event
13799
* manager, so the implementer should not normally need to execute
13800
* this function at all.
13802
* @param {Event} e the event parameter from the handler
13803
* @param {HTMLElement} el the element the listener was attached to
13804
* @return {Event} the event
13807
getEvent: function(e, el, noFacade) {
13808
var ev = e || win.event;
13810
return (noFacade) ? ev :
13811
new Y.DOMEventFacade(ev, el, _wrappers['event:' + Y.stamp(el) + e.type]);
13815
* Generates an unique ID for the element if it does not already
13817
* @method generateId
13818
* @param el the element to create the id for
13819
* @return {string} the resulting id of the element
13822
generateId: function(el) {
13823
return Y.DOM.generateID(el);
13827
* We want to be able to use getElementsByTagName as a collection
13828
* to attach a group of events to. Unfortunately, different
13829
* browsers return different types of collections. This function
13830
* tests to determine if the object is array-like. It will also
13831
* fail if the object is an array, but is empty.
13832
* @method _isValidCollection
13833
* @param o the object to test
13834
* @return {boolean} true if the object is array-like and populated
13835
* @deprecated was not meant to be used directly
13839
_isValidCollection: shouldIterate,
13842
* hook up any deferred listeners
13847
_load: function(e) {
13848
if (!_loadComplete) {
13849
// Y.log('Load Complete', 'info', 'event');
13850
_loadComplete = true;
13852
// Just in case DOMReady did not go off for some reason
13855
Y.fire(EVENT_READY);
13858
// Available elements may not have been detected before the
13859
// window load event fires. Try to find them now so that the
13860
// the user is more likely to get the onAvailable notifications
13861
// before the window load notification
13867
* Polling function that runs before the onload event fires,
13868
* attempting to attach to DOM Nodes as soon as they are
13874
_poll: function() {
13875
if (Event.locked) {
13879
if (Y.UA.ie && !YUI.Env.DOMReady) {
13880
// Hold off if DOMReady has not fired and check current
13881
// readyState to protect against the IE operation aborted
13883
Event.startInterval();
13887
Event.locked = true;
13889
// Y.log.debug("poll");
13890
// keep trying until after the page is loaded. We need to
13891
// check the page load state prior to trying to bind the
13892
// elements so that we can be certain all elements have been
13893
// tested appropriately
13894
var i, len, item, el, notAvail, executeItem,
13895
tryAgain = !_loadComplete;
13898
tryAgain = (_retryCount > 0);
13904
executeItem = function (el, item) {
13905
var context, ov = item.override;
13907
if (item.override) {
13909
context = item.obj;
13916
item.fn.call(context, item.obj);
13918
context = item.obj || Y.one(el);
13919
item.fn.apply(context, (Y.Lang.isArray(ov)) ? ov : []);
13924
for (i=0,len=_avail.length; i<len; ++i) {
13926
if (item && !item.checkReady) {
13928
// el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
13929
el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
13932
// Y.log('avail: ' + el);
13933
executeItem(el, item);
13936
// Y.log('NOT avail: ' + el);
13937
notAvail.push(item);
13943
for (i=0,len=_avail.length; i<len; ++i) {
13945
if (item && item.checkReady) {
13947
// el = (item.compat) ? Y.DOM.byId(item.id) : Y.one(item.id);
13948
el = (item.compat) ? Y.DOM.byId(item.id) : Y.Selector.query(item.id, null, true);
13951
// The element is available, but not necessarily ready
13952
// @todo should we test parentNode.nextSibling?
13953
if (_loadComplete || (el.get && el.get('nextSibling')) || el.nextSibling) {
13954
executeItem(el, item);
13958
notAvail.push(item);
13963
_retryCount = (notAvail.length === 0) ? 0 : _retryCount - 1;
13966
// we may need to strip the nulled out items here
13967
Event.startInterval();
13969
clearInterval(Event._interval);
13970
Event._interval = null;
13973
Event.locked = false;
13980
* Removes all listeners attached to the given element via addListener.
13981
* Optionally, the node's children can also be purged.
13982
* Optionally, you can specify a specific type of event to remove.
13983
* @method purgeElement
13984
* @param {HTMLElement} el the element to purge
13985
* @param {boolean} recurse recursively purge this element's children
13986
* as well. Use with caution.
13987
* @param {string} type optional type of listener to purge. If
13988
* left out, all listeners will be removed
13991
purgeElement: function(el, recurse, type) {
13992
// var oEl = (Y.Lang.isString(el)) ? Y.one(el) : el,
13993
var oEl = (Y.Lang.isString(el)) ? Y.Selector.query(el, null, true) : el,
13994
lis = Event.getListeners(oEl, type), i, len, children, child;
13996
if (recurse && oEl) {
13998
children = Y.Selector.query('*', oEl);
14000
len = children.length;
14001
for (; i < len; ++i) {
14002
child = Event.getListeners(children[i], type);
14004
lis = lis.concat(child);
14010
for (i = 0, len = lis.length; i < len; ++i) {
14011
lis[i].detachAll();
14018
* Removes all object references and the DOM proxy subscription for
14019
* a given event for a DOM node.
14022
* @param wrapper {CustomEvent} Custom event proxy for the DOM
14028
_clean: function (wrapper) {
14029
var key = wrapper.key,
14030
domkey = wrapper.domkey;
14032
remove(wrapper.el, wrapper.type, wrapper.fn, wrapper.capture);
14033
delete _wrappers[key];
14034
delete Y._yuievt.events[key];
14035
if (_el_events[domkey]) {
14036
delete _el_events[domkey][key];
14037
if (!Y.Object.size(_el_events[domkey])) {
14038
delete _el_events[domkey];
14044
* Returns all listeners attached to the given element via addListener.
14045
* Optionally, you can specify a specific type of event to return.
14046
* @method getListeners
14047
* @param el {HTMLElement|string} the element or element id to inspect
14048
* @param type {string} optional type of listener to return. If
14049
* left out, all listeners will be returned
14050
* @return {Y.Custom.Event} the custom event wrapper for the DOM event(s)
14053
getListeners: function(el, type) {
14054
var ek = Y.stamp(el, true), evts = _el_events[ek],
14055
results=[] , key = (type) ? 'event:' + ek + type : null,
14056
adapters = _eventenv.plugins;
14063
// look for synthetic events
14064
if (adapters[type] && adapters[type].eventDef) {
14069
results.push(evts[key]);
14072
// get native events as well
14075
results.push(evts[key]);
14079
Y.each(evts, function(v, k) {
14084
return (results.length) ? results : null;
14088
* Removes all listeners registered by pe.event. Called
14089
* automatically during the unload event.
14094
_unload: function(e) {
14095
Y.each(_wrappers, function(v, k) {
14096
if (v.type == 'unload') {
14101
remove(win, "unload", onUnload);
14105
* Adds a DOM event directly without the caching, cleanup, context adj, etc
14107
* @method nativeAdd
14108
* @param {HTMLElement} el the element to bind the handler to
14109
* @param {string} type the type of event handler
14110
* @param {function} fn the callback to invoke
14111
* @param {boolen} capture capture or bubble phase
14118
* Basic remove listener
14120
* @method nativeRemove
14121
* @param {HTMLElement} el the element to bind the handler to
14122
* @param {string} type the type of event handler
14123
* @param {function} fn the callback to invoke
14124
* @param {boolen} capture capture or bubble phase
14128
nativeRemove: remove
14135
if (config.injected || YUI.Env.windowLoaded) {
14138
add(win, "load", onLoad);
14141
// Process onAvailable/onContentReady items when when the DOM is ready in IE
14143
Y.on(EVENT_READY, Event._poll);
14146
add(win, "unload", onUnload);
14148
Event.Custom = Y.CustomEvent;
14149
Event.Subscriber = Y.Subscriber;
14150
Event.Target = Y.EventTarget;
14151
Event.Handle = Y.EventHandle;
14152
Event.Facade = Y.EventFacade;
14159
* DOM event listener abstraction layer
14161
* @submodule event-base
14165
* Executes the callback as soon as the specified element
14166
* is detected in the DOM. This function expects a selector
14167
* string for the element(s) to detect. If you already have
14168
* an element reference, you don't need this event.
14170
* @param type {string} 'available'
14171
* @param fn {function} the callback function to execute.
14172
* @param el {string} an selector for the element(s) to attach
14173
* @param context optional argument that specifies what 'this' refers to.
14174
* @param args* 0..n additional arguments to pass on to the callback function.
14175
* These arguments will be added after the event object.
14176
* @return {EventHandle} the detach handle
14179
Y.Env.evt.plugins.available = {
14180
on: function(type, fn, id, o) {
14181
var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
14182
return Y.Event.onAvailable.call(Y.Event, id, fn, o, a);
14187
* Executes the callback as soon as the specified element
14188
* is detected in the DOM with a nextSibling property
14189
* (indicating that the element's children are available).
14190
* This function expects a selector
14191
* string for the element(s) to detect. If you already have
14192
* an element reference, you don't need this event.
14193
* @event contentready
14194
* @param type {string} 'contentready'
14195
* @param fn {function} the callback function to execute.
14196
* @param el {string} an selector for the element(s) to attach.
14197
* @param context optional argument that specifies what 'this' refers to.
14198
* @param args* 0..n additional arguments to pass on to the callback function.
14199
* These arguments will be added after the event object.
14200
* @return {EventHandle} the detach handle
14203
Y.Env.evt.plugins.contentready = {
14204
on: function(type, fn, id, o) {
14205
var a = arguments.length > 4 ? Y.Array(arguments, 4, true) : null;
14206
return Y.Event.onContentReady.call(Y.Event, id, fn, o, a);
14211
}, '3.4.1' ,{requires:['event-custom-base']});
14212
YUI.add('pluginhost-base', function(Y) {
14215
* Provides the augmentable PluginHost interface, which can be added to any class.
14216
* @module pluginhost
14220
* Provides the augmentable PluginHost interface, which can be added to any class.
14221
* @module pluginhost-base
14226
* An augmentable class, which provides the augmented class with the ability to host plugins.
14227
* It adds <a href="#method_plug">plug</a> and <a href="#method_unplug">unplug</a> methods to the augmented class, which can
14228
* be used to add or remove plugins from instances of the class.
14231
* <p>Plugins can also be added through the constructor configuration object passed to the host class' constructor using
14232
* the "plugins" property. Supported values for the "plugins" property are those defined by the <a href="#method_plug">plug</a> method.
14234
* For example the following code would add the AnimPlugin and IOPlugin to Overlay (the plugin host):
14236
* var o = new Overlay({plugins: [ AnimPlugin, {fn:IOPlugin, cfg:{section:"header"}}]});
14240
* Plug.Host's protected <a href="#method_initPlugins">_initPlugins</a> and <a href="#method_destroyPlugins">_destroyPlugins</a>
14241
* methods should be invoked by the host class at the appropriate point in the host's lifecyle.
14244
* @class Plugin.Host
14249
function PluginHost() {
14250
this._plugins = {};
14253
PluginHost.prototype = {
14256
* Adds a plugin to the host object. This will instantiate the
14257
* plugin and attach it to the configured namespace on the host object.
14261
* @param P {Function | Object |Array} Accepts the plugin class, or an
14262
* object with a "fn" property specifying the plugin class and
14263
* a "cfg" property specifying the configuration for the Plugin.
14265
* Additionally an Array can also be passed in, with the above function or
14266
* object values, allowing the user to add multiple plugins in a single call.
14268
* @param config (Optional) If the first argument is the plugin class, the second argument
14269
* can be the configuration for the plugin.
14270
* @return {Base} A reference to the host object
14272
plug: function(Plugin, config) {
14275
if (L.isArray(Plugin)) {
14276
for (i = 0, ln = Plugin.length; i < ln; i++) {
14277
this.plug(Plugin[i]);
14280
if (Plugin && !L.isFunction(Plugin)) {
14281
config = Plugin.cfg;
14282
Plugin = Plugin.fn;
14285
// Plugin should be fn by now
14286
if (Plugin && Plugin.NS) {
14289
config = config || {};
14290
config.host = this;
14292
if (this.hasPlugin(ns)) {
14294
this[ns].setAttrs(config);
14296
// Create new instance
14297
this[ns] = new Plugin(config);
14298
this._plugins[ns] = Plugin;
14301
else { Y.log("Attempt to plug in an invalid plugin. Host:" + this + ", Plugin:" + Plugin); }
14307
* Removes a plugin from the host object. This will destroy the
14308
* plugin instance and delete the namepsace from the host object.
14311
* @param {String | Function} plugin The namespace of the plugin, or the plugin class with the static NS namespace property defined. If not provided,
14312
* all registered plugins are unplugged.
14313
* @return {Base} A reference to the host object
14316
unplug: function(plugin) {
14318
plugins = this._plugins;
14321
if (L.isFunction(plugin)) {
14323
if (ns && (!plugins[ns] || plugins[ns] !== plugin)) {
14330
this[ns].destroy();
14334
delete plugins[ns];
14338
for (ns in this._plugins) {
14339
if (this._plugins.hasOwnProperty(ns)) {
14348
* Determines if a plugin has plugged into this host.
14350
* @method hasPlugin
14351
* @param {String} ns The plugin's namespace
14352
* @return {boolean} returns true, if the plugin has been plugged into this host, false otherwise.
14354
hasPlugin : function(ns) {
14355
return (this._plugins[ns] && this[ns]);
14359
* Initializes static plugins registered on the host (using the
14360
* Base.plug static method) and any plugins passed to the
14361
* instance through the "plugins" configuration property.
14363
* @method _initPlugins
14364
* @param {Config} config The configuration object with property name/value pairs.
14368
_initPlugins: function(config) {
14369
this._plugins = this._plugins || {};
14371
if (this._initConfigPlugins) {
14372
this._initConfigPlugins(config);
14377
* Unplugs and destroys all plugins on the host
14378
* @method _destroyPlugins
14381
_destroyPlugins: function() {
14386
Y.namespace("Plugin").Host = PluginHost;
14389
}, '3.4.1' ,{requires:['yui-base']});
14390
YUI.add('pluginhost-config', function(Y) {
14393
* Adds pluginhost constructor configuration and static configuration support
14394
* @submodule pluginhost-config
14397
var PluginHost = Y.Plugin.Host,
14401
* A protected initialization method, used by the host class to initialize
14402
* plugin configurations passed the constructor, through the config object.
14404
* Host objects should invoke this method at the appropriate time in their
14405
* construction lifecycle.
14407
* @method _initConfigPlugins
14408
* @param {Object} config The configuration object passed to the constructor
14412
PluginHost.prototype._initConfigPlugins = function(config) {
14414
// Class Configuration
14415
var classes = (this._getClasses) ? this._getClasses() : [this.constructor],
14418
constructor, i, classPlug, classUnplug, pluginClassName;
14420
// TODO: Room for optimization. Can we apply statically/unplug in same pass?
14421
for (i = classes.length - 1; i >= 0; i--) {
14422
constructor = classes[i];
14424
classUnplug = constructor._UNPLUG;
14426
// subclasses over-write
14427
Y.mix(unplug, classUnplug, true);
14430
classPlug = constructor._PLUG;
14432
// subclasses over-write
14433
Y.mix(plug, classPlug, true);
14437
for (pluginClassName in plug) {
14438
if (plug.hasOwnProperty(pluginClassName)) {
14439
if (!unplug[pluginClassName]) {
14440
this.plug(plug[pluginClassName]);
14445
// User Configuration
14446
if (config && config.plugins) {
14447
this.plug(config.plugins);
14452
* Registers plugins to be instantiated at the class level (plugins
14453
* which should be plugged into every instance of the class by default).
14455
* @method Plugin.Host.plug
14458
* @param {Function} hostClass The host class on which to register the plugins
14459
* @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined)
14460
* @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
14462
PluginHost.plug = function(hostClass, plugin, config) {
14463
// Cannot plug into Base, since Plugins derive from Base [ will cause infinite recurrsion ]
14466
if (hostClass !== Y.Base) {
14467
hostClass._PLUG = hostClass._PLUG || {};
14469
if (!L.isArray(plugin)) {
14471
plugin = {fn:plugin, cfg:config};
14476
for (i = 0, l = plugin.length; i < l;i++) {
14478
name = p.NAME || p.fn.NAME;
14479
hostClass._PLUG[name] = p;
14485
* Unregisters any class level plugins which have been registered by the host class, or any
14486
* other class in the hierarchy.
14488
* @method Plugin.Host.unplug
14491
* @param {Function} hostClass The host class from which to unregister the plugins
14492
* @param {Function | Array} plugin The plugin class, or an array of plugin classes
14494
PluginHost.unplug = function(hostClass, plugin) {
14497
if (hostClass !== Y.Base) {
14498
hostClass._UNPLUG = hostClass._UNPLUG || {};
14500
if (!L.isArray(plugin)) {
14504
for (i = 0, l = plugin.length; i < l; i++) {
14507
if (!hostClass._PLUG[name]) {
14508
hostClass._UNPLUG[name] = p;
14510
delete hostClass._PLUG[name];
14517
}, '3.4.1' ,{requires:['pluginhost-base']});
14518
YUI.add('event-delegate', function(Y) {
14521
* Adds event delegation support to the library.
14524
* @submodule event-delegate
14527
var toArray = Y.Array,
14529
isString = YLang.isString,
14530
isObject = YLang.isObject,
14531
isArray = YLang.isArray,
14532
selectorTest = Y.Selector.test,
14533
detachCategories = Y.Env.evt.handles;
14536
* <p>Sets up event delegation on a container element. The delegated event
14537
* will use a supplied selector or filtering function to test if the event
14538
* references at least one node that should trigger the subscription
14541
* <p>Selector string filters will trigger the callback if the event originated
14542
* from a node that matches it or is contained in a node that matches it.
14543
* Function filters are called for each Node up the parent axis to the
14544
* subscribing container node, and receive at each level the Node and the event
14545
* object. The function should return true (or a truthy value) if that Node
14546
* should trigger the subscription callback. Note, it is possible for filters
14547
* to match multiple Nodes for a single event. In this case, the delegate
14548
* callback will be executed for each matching Node.</p>
14550
* <p>For each matching Node, the callback will be executed with its 'this'
14551
* object set to the Node matched by the filter (unless a specific context was
14552
* provided during subscription), and the provided event's
14553
* <code>currentTarget</code> will also be set to the matching Node. The
14554
* containing Node from which the subscription was originally made can be
14555
* referenced as <code>e.container</code>.
14558
* @param type {String} the event type to delegate
14559
* @param fn {Function} the callback function to execute. This function
14560
* will be provided the event object for the delegated event.
14561
* @param el {String|node} the element that is the delegation container
14562
* @param spec {string|Function} a selector that must match the target of the
14563
* event or a function to test target and its parents for a match
14564
* @param context optional argument that specifies what 'this' refers to.
14565
* @param args* 0..n additional arguments to pass on to the callback function.
14566
* These arguments will be added after the event object.
14567
* @return {EventHandle} the detach handle
14570
function delegate(type, fn, el, filter) {
14571
var args = toArray(arguments, 0, true),
14572
query = isString(el) ? el : null,
14573
typeBits, synth, container, categories, cat, i, len, handles, handle;
14575
// Support Y.delegate({ click: fnA, key: fnB }, context, filter, ...);
14576
// and Y.delegate(['click', 'key'], fn, context, filter, ...);
14577
if (isObject(type)) {
14580
if (isArray(type)) {
14581
for (i = 0, len = type.length; i < len; ++i) {
14583
handles.push(Y.delegate.apply(Y, args));
14586
// Y.delegate({'click', fn}, context, filter) =>
14587
// Y.delegate('click', fn, context, filter)
14588
args.unshift(null); // one arg becomes two; need to make space
14591
if (type.hasOwnProperty(i)) {
14594
handles.push(Y.delegate.apply(Y, args));
14599
return new Y.EventHandle(handles);
14602
typeBits = type.split(/\|/);
14604
if (typeBits.length > 1) {
14605
cat = typeBits.shift();
14606
args[0] = type = typeBits.shift();
14609
synth = Y.Node.DOM_EVENTS[type];
14611
if (isObject(synth) && synth.delegate) {
14612
handle = synth.delegate.apply(synth, arguments);
14616
if (!type || !fn || !el || !filter) {
14617
Y.log("delegate requires type, callback, parent, & filter", "warn");
14621
container = (query) ? Y.Selector.query(query, null, true) : el;
14623
if (!container && isString(el)) {
14624
handle = Y.on('available', function () {
14625
Y.mix(handle, Y.delegate.apply(Y, args), true);
14629
if (!handle && container) {
14630
args.splice(2, 2, container); // remove the filter
14632
handle = Y.Event._attach(args, { facade: false });
14633
handle.sub.filter = filter;
14634
handle.sub._notify = delegate.notifySub;
14638
if (handle && cat) {
14639
categories = detachCategories[cat] || (detachCategories[cat] = {});
14640
categories = categories[type] || (categories[type] = []);
14641
categories.push(handle);
14648
* Overrides the <code>_notify</code> method on the normal DOM subscription to
14649
* inject the filtering logic and only proceed in the case of a match.
14651
* @method delegate.notifySub
14652
* @param thisObj {Object} default 'this' object for the callback
14653
* @param args {Array} arguments passed to the event's <code>fire()</code>
14654
* @param ce {CustomEvent} the custom event managing the DOM subscriptions for
14655
* the subscribed event on the subscribing node.
14656
* @return {Boolean} false if the event was stopped
14661
delegate.notifySub = function (thisObj, args, ce) {
14662
// Preserve args for other subscribers
14663
args = args.slice();
14665
args.push.apply(args, this.args);
14668
// Only notify subs if the event occurred on a targeted element
14669
var currentTarget = delegate._applyFilter(this.filter, args, ce),
14670
//container = e.currentTarget,
14673
if (currentTarget) {
14674
// Support multiple matches up the the container subtree
14675
currentTarget = toArray(currentTarget);
14677
// The second arg is the currentTarget, but we'll be reusing this
14678
// facade, replacing the currentTarget for each use, so it doesn't
14679
// matter what element we seed it with.
14680
e = args[0] = new Y.DOMEventFacade(args[0], ce.el, ce);
14682
e.container = Y.one(ce.el);
14684
for (i = 0, len = currentTarget.length; i < len && !e.stopped; ++i) {
14685
e.currentTarget = Y.one(currentTarget[i]);
14687
ret = this.fn.apply(this.context || e.currentTarget, args);
14689
if (ret === false) { // stop further notifications
14699
* <p>Compiles a selector string into a filter function to identify whether
14700
* Nodes along the parent axis of an event's target should trigger event
14701
* notification.</p>
14703
* <p>This function is memoized, so previously compiled filter functions are
14704
* returned if the same selector string is provided.</p>
14706
* <p>This function may be useful when defining synthetic events for delegate
14709
* @method delegate.compileFilter
14710
* @param selector {String} the selector string to base the filtration on
14711
* @return {Function}
14715
delegate.compileFilter = Y.cached(function (selector) {
14716
return function (target, e) {
14717
return selectorTest(target._node, selector, e.currentTarget._node);
14722
* Walks up the parent axis of an event's target, and tests each element
14723
* against a supplied filter function. If any Nodes, including the container,
14724
* satisfy the filter, the delegated callback will be triggered for each.
14726
* @method delegate._applyFilter
14727
* @param filter {Function} boolean function to test for inclusion in event
14729
* @param args {Array} the arguments that would be passed to subscribers
14730
* @param ce {CustomEvent} the DOM event wrapper
14731
* @return {Node|Node[]|undefined} The Node or Nodes that satisfy the filter
14734
delegate._applyFilter = function (filter, args, ce) {
14736
container = ce.el, // facadeless events in IE, have no e.currentTarget
14737
target = e.target || e.srcElement,
14739
isContainer = false;
14741
// Resolve text nodes to their containing element
14742
if (target.nodeType === 3) {
14743
target = target.parentNode;
14746
// passing target as the first arg rather than leaving well enough alone
14747
// making 'this' in the filter function refer to the target. This is to
14748
// support bound filter functions.
14749
args.unshift(target);
14751
if (isString(filter)) {
14753
isContainer = (target === container);
14754
if (selectorTest(target, filter, (isContainer ?null: container))) {
14755
match.push(target);
14762
target = target.parentNode;
14765
// filter functions are implementer code and should receive wrappers
14766
args[0] = Y.one(target);
14767
args[1] = new Y.DOMEventFacade(e, container, ce);
14770
// filter(target, e, extra args...) - this === target
14771
if (filter.apply(args[0], args)) {
14772
match.push(target);
14775
if (target === container) {
14779
target = target.parentNode;
14780
args[0] = Y.one(target);
14782
args[1] = e; // restore the raw DOM event
14785
if (match.length <= 1) {
14786
match = match[0]; // single match or undefined
14789
// remove the target
14796
* Sets up event delegation on a container element. The delegated event
14797
* will use a supplied filter to test if the callback should be executed.
14798
* This filter can be either a selector string or a function that returns
14799
* a Node to use as the currentTarget for the event.
14801
* The event object for the delegated event is supplied to the callback
14802
* function. It is modified slightly in order to support all properties
14803
* that may be needed for event delegation. 'currentTarget' is set to
14804
* the element that matched the selector string filter or the Node returned
14805
* from the filter function. 'container' is set to the element that the
14806
* listener is delegated from (this normally would be the 'currentTarget').
14808
* Filter functions will be called with the arguments that would be passed to
14809
* the callback function, including the event object as the first parameter.
14810
* The function should return false (or a falsey value) if the success criteria
14811
* aren't met, and the Node to use as the event's currentTarget and 'this'
14812
* object if they are.
14815
* @param type {string} the event type to delegate
14816
* @param fn {function} the callback function to execute. This function
14817
* will be provided the event object for the delegated event.
14818
* @param el {string|node} the element that is the delegation container
14819
* @param filter {string|function} a selector that must match the target of the
14820
* event or a function that returns a Node or false.
14821
* @param context optional argument that specifies what 'this' refers to.
14822
* @param args* 0..n additional arguments to pass on to the callback function.
14823
* These arguments will be added after the event object.
14824
* @return {EventHandle} the detach handle
14827
Y.delegate = Y.Event.delegate = delegate;
14830
}, '3.4.1' ,{requires:['node-base']});
14831
YUI.add('node-event-delegate', function(Y) {
14834
* Functionality to make the node a delegated event container
14836
* @submodule node-event-delegate
14840
* <p>Sets up a delegation listener for an event occurring inside the Node.
14841
* The delegated event will be verified against a supplied selector or
14842
* filtering function to test if the event references at least one node that
14843
* should trigger the subscription callback.</p>
14845
* <p>Selector string filters will trigger the callback if the event originated
14846
* from a node that matches it or is contained in a node that matches it.
14847
* Function filters are called for each Node up the parent axis to the
14848
* subscribing container node, and receive at each level the Node and the event
14849
* object. The function should return true (or a truthy value) if that Node
14850
* should trigger the subscription callback. Note, it is possible for filters
14851
* to match multiple Nodes for a single event. In this case, the delegate
14852
* callback will be executed for each matching Node.</p>
14854
* <p>For each matching Node, the callback will be executed with its 'this'
14855
* object set to the Node matched by the filter (unless a specific context was
14856
* provided during subscription), and the provided event's
14857
* <code>currentTarget</code> will also be set to the matching Node. The
14858
* containing Node from which the subscription was originally made can be
14859
* referenced as <code>e.container</code>.
14862
* @param type {String} the event type to delegate
14863
* @param fn {Function} the callback function to execute. This function
14864
* will be provided the event object for the delegated event.
14865
* @param spec {String|Function} a selector that must match the target of the
14866
* event or a function to test target and its parents for a match
14867
* @param context {Object} optional argument that specifies what 'this' refers to.
14868
* @param args* {any} 0..n additional arguments to pass on to the callback function.
14869
* These arguments will be added after the event object.
14870
* @return {EventHandle} the detach handle
14873
Y.Node.prototype.delegate = function(type) {
14875
var args = Y.Array(arguments, 0, true),
14876
index = (Y.Lang.isObject(type) && !Y.Lang.isArray(type)) ? 1 : 2;
14878
args.splice(index, 0, this._node);
14880
return Y.delegate.apply(Y, args);
14884
}, '3.4.1' ,{requires:['node-base', 'event-delegate']});
14885
YUI.add('node-pluginhost', function(Y) {
14889
* @submodule node-pluginhost
14893
* Registers plugins to be instantiated at the class level (plugins
14894
* which should be plugged into every instance of Node by default).
14899
* @param {Function | Array} plugin Either the plugin class, an array of plugin classes or an array of objects (with fn and cfg properties defined)
14900
* @param {Object} config (Optional) If plugin is the plugin class, the configuration for the plugin
14902
Y.Node.plug = function() {
14903
var args = Y.Array(arguments);
14904
args.unshift(Y.Node);
14905
Y.Plugin.Host.plug.apply(Y.Base, args);
14910
* Unregisters any class level plugins which have been registered by the Node
14915
* @param {Function | Array} plugin The plugin class, or an array of plugin classes
14917
Y.Node.unplug = function() {
14918
var args = Y.Array(arguments);
14919
args.unshift(Y.Node);
14920
Y.Plugin.Host.unplug.apply(Y.Base, args);
14924
Y.mix(Y.Node, Y.Plugin.Host, false, null, 1);
14926
// allow batching of plug/unplug via NodeList
14927
// doesn't use NodeList.importMethod because we need real Nodes (not tmpNode)
14928
Y.NodeList.prototype.plug = function() {
14929
var args = arguments;
14930
Y.NodeList.each(this, function(node) {
14931
Y.Node.prototype.plug.apply(Y.one(node), args);
14935
Y.NodeList.prototype.unplug = function() {
14936
var args = arguments;
14937
Y.NodeList.each(this, function(node) {
14938
Y.Node.prototype.unplug.apply(Y.one(node), args);
14943
}, '3.4.1' ,{requires:['node-base', 'pluginhost']});
14944
YUI.add('node-screen', function(Y) {
14947
* Extended Node interface for managing regions and screen positioning.
14948
* Adds support for positioning elements and normalizes window size and scroll detection.
14950
* @submodule node-screen
14953
// these are all "safe" returns, no wrapping required
14956
* Returns the inner width of the viewport (exludes scrollbar).
14964
* Returns the inner height of the viewport (exludes scrollbar).
14965
* @config winHeight
14972
* @config winHeight
14979
* @config docHeight
14985
* Pixel distance the page has been scrolled horizontally
14986
* @config docScrollX
14992
* Pixel distance the page has been scrolled vertically
14993
* @config docScrollY
14999
Y.Node.ATTRS[name] = {
15000
getter: function() {
15001
var args = Array.prototype.slice.call(arguments);
15002
args.unshift(Y.Node.getDOMNode(this));
15004
return Y.DOM[name].apply(this, args);
15010
Y.Node.ATTRS.scrollLeft = {
15011
getter: function() {
15012
var node = Y.Node.getDOMNode(this);
15013
return ('scrollLeft' in node) ? node.scrollLeft : Y.DOM.docScrollX(node);
15016
setter: function(val) {
15017
var node = Y.Node.getDOMNode(this);
15019
if ('scrollLeft' in node) {
15020
node.scrollLeft = val;
15021
} else if (node.document || node.nodeType === 9) {
15022
Y.DOM._getWin(node).scrollTo(val, Y.DOM.docScrollY(node)); // scroll window if win or doc
15025
Y.log('unable to set scrollLeft for ' + node, 'error', 'Node');
15030
Y.Node.ATTRS.scrollTop = {
15031
getter: function() {
15032
var node = Y.Node.getDOMNode(this);
15033
return ('scrollTop' in node) ? node.scrollTop : Y.DOM.docScrollY(node);
15036
setter: function(val) {
15037
var node = Y.Node.getDOMNode(this);
15039
if ('scrollTop' in node) {
15040
node.scrollTop = val;
15041
} else if (node.document || node.nodeType === 9) {
15042
Y.DOM._getWin(node).scrollTo(Y.DOM.docScrollX(node), val); // scroll window if win or doc
15045
Y.log('unable to set scrollTop for ' + node, 'error', 'Node');
15050
Y.Node.importMethod(Y.DOM, [
15052
* Gets the current position of the node in page coordinates.
15055
* @return {Array} The XY position of the node
15060
* Set the position of the node in page coordinates, regardless of how the node is positioned.
15062
* @param {Array} xy Contains X & Y values for new position (coordinates are page-based)
15068
* Gets the current position of the node in page coordinates.
15070
* @return {Int} The X position of the node
15075
* Set the position of the node in page coordinates, regardless of how the node is positioned.
15077
* @param {Int} x X value for new position (coordinates are page-based)
15083
* Gets the current position of the node in page coordinates.
15085
* @return {Int} The Y position of the node
15090
* Set the position of the node in page coordinates, regardless of how the node is positioned.
15092
* @param {Int} y Y value for new position (coordinates are page-based)
15098
* Swaps the XY position of this node with another node.
15100
* @param {Y.Node || HTMLElement} otherNode The node to swap with.
15108
* @submodule node-screen
15112
* Returns a region object for the node
15117
Y.Node.ATTRS.region = {
15118
getter: function() {
15119
var node = this.getDOMNode(),
15122
if (node && !node.tagName) {
15123
if (node.nodeType === 9) { // document
15124
node = node.documentElement;
15127
if (Y.DOM.isWindow(node)) {
15128
region = Y.DOM.viewportRegion(node);
15130
region = Y.DOM.region(node);
15137
* Returns a region object for the node's viewport
15138
* @config viewportRegion
15141
Y.Node.ATTRS.viewportRegion = {
15142
getter: function() {
15143
return Y.DOM.viewportRegion(Y.Node.getDOMNode(this));
15147
Y.Node.importMethod(Y.DOM, 'inViewportRegion');
15149
// these need special treatment to extract 2nd node arg
15151
* Compares the intersection of the node with another node or region
15152
* @method intersect
15154
* @param {Node|Object} node2 The node or region to compare with.
15155
* @param {Object} altRegion An alternate region to use (rather than this node's).
15156
* @return {Object} An object representing the intersection of the regions.
15158
Y.Node.prototype.intersect = function(node2, altRegion) {
15159
var node1 = Y.Node.getDOMNode(this);
15160
if (Y.instanceOf(node2, Y.Node)) { // might be a region object
15161
node2 = Y.Node.getDOMNode(node2);
15163
return Y.DOM.intersect(node1, node2, altRegion);
15167
* Determines whether or not the node is within the giving region.
15169
* @param {Node|Object} node2 The node or region to compare with.
15170
* @param {Boolean} all Whether or not all of the node must be in the region.
15171
* @param {Object} altRegion An alternate region to use (rather than this node's).
15172
* @return {Object} An object representing the intersection of the regions.
15174
Y.Node.prototype.inRegion = function(node2, all, altRegion) {
15175
var node1 = Y.Node.getDOMNode(this);
15176
if (Y.instanceOf(node2, Y.Node)) { // might be a region object
15177
node2 = Y.Node.getDOMNode(node2);
15179
return Y.DOM.inRegion(node1, node2, all, altRegion);
15183
}, '3.4.1' ,{requires:['node-base', 'dom-screen']});
15184
YUI.add('node-style', function(Y) {
15188
* Extended Node interface for managing node styles.
15190
* @submodule node-style
15195
* Returns the style's current value.
15198
* @param {String} attr The style attribute to retrieve.
15199
* @return {String} The current value of the style property for the element.
15204
* Returns the computed value for the given style property.
15205
* @method getComputedStyle
15206
* @param {String} attr The style attribute to retrieve.
15207
* @return {String} The computed value of the style property for the element.
15209
'getComputedStyle',
15212
* Sets a style property of the node.
15214
* @param {String} attr The style attribute to set.
15215
* @param {String|Number} val The value.
15221
* Sets multiple style properties on the node.
15222
* @method setStyles
15223
* @param {Object} hash An object literal of property:value pairs.
15228
Y.Node.importMethod(Y.DOM, methods);
15230
* Returns an array of values for each node.
15233
* @see Node.getStyle
15234
* @param {String} attr The style attribute to retrieve.
15235
* @return {Array} The current values of the style property for the element.
15239
* Returns an array of the computed value for each node.
15240
* @method getComputedStyle
15241
* @see Node.getComputedStyle
15242
* @param {String} attr The style attribute to retrieve.
15243
* @return {Array} The computed values for each node.
15247
* Sets a style property on each node.
15249
* @see Node.setStyle
15250
* @param {String} attr The style attribute to set.
15251
* @param {String|Number} val The value.
15256
* Sets multiple style properties on each node.
15257
* @method setStyles
15258
* @see Node.setStyles
15259
* @param {Object} hash An object literal of property:value pairs.
15262
Y.NodeList.importMethod(Y.Node.prototype, methods);
15266
}, '3.4.1' ,{requires:['dom-style', 'node-base']});
15267
YUI.add('querystring-stringify-simple', function(Y) {
15271
* <p>Provides Y.QueryString.stringify method for converting objects to Query Strings.
15272
* This is a subset implementation of the full querystring-stringify.</p>
15273
* <p>This module provides the bare minimum functionality (encoding a hash of simple values),
15274
* without the additional support for nested data structures. Every key-value pair is
15275
* encoded by encodeURIComponent.</p>
15276
* <p>This module provides a minimalistic way for io to handle single-level objects
15277
* as transaction data.</p>
15279
* @module querystring
15280
* @submodule querystring-stringify-simple
15285
var QueryString = Y.namespace("QueryString"),
15286
EUC = encodeURIComponent;
15289
* <p>Converts a simple object to a Query String representation.</p>
15290
* <p>Nested objects, Arrays, and so on, are not supported.</p>
15292
* @method stringify
15295
* @submodule querystring-stringify-simple
15296
* @param obj {Object} A single-level object to convert to a querystring.
15297
* @param cfg {Object} (optional) Configuration object. In the simple
15298
* module, only the arrayKey setting is
15299
* supported. When set to true, the key of an
15300
* array will have the '[]' notation appended
15304
QueryString.stringify = function (obj, c) {
15306
// Default behavior is false; standard key notation.
15307
s = c && c.arrayKey ? true : false,
15311
if (obj.hasOwnProperty(key)) {
15312
if (Y.Lang.isArray(obj[key])) {
15313
for (i = 0, l = obj[key].length; i < l; i++) {
15314
qs.push(EUC(s ? key + '[]' : key) + '=' + EUC(obj[key][i]));
15318
qs.push(EUC(key) + '=' + EUC(obj[key]));
15323
return qs.join('&');
15327
}, '3.4.1' ,{requires:['yui-base']});
15328
YUI.add('io-base', function(Y) {
15331
* Base IO functionality. Provides basic XHR transport support.
15333
* @submodule io-base
15336
// Window reference
15338
// List of events that comprise the IO event lifecycle.
15339
E = ['start', 'complete', 'end', 'success', 'failure'],
15340
// Whitelist of used XHR response object properties.
15341
P = ['status', 'statusText', 'responseText', 'responseXML'],
15342
aH = 'getAllResponseHeaders',
15343
oH = 'getResponseHeader',
15345
xhr = w.XMLHttpRequest,
15346
xdr = w.XDomainRequest,
15350
* The io class is a utility that brokers HTTP requests through a simplified
15351
* interface. Specifically, it allows JavaScript to make HTTP requests to
15352
* a resource without a page reload. The underlying transport for making
15353
* same-domain requests is the XMLHttpRequest object. YUI.io can also use
15354
* Flash, if specified as a transport, for cross-domain requests.
15358
* @param {object} c - Object of EventTarget's publish method configurations
15359
* used to configure IO's events.
15364
io._uid = 'io:' + _i++;
15366
Y.io._map[io._uid] = io;
15370
//--------------------------------------
15372
//--------------------------------------
15375
* @description A counter that increments for each transaction.
15384
* @description Object of IO HTTP headers sent with each transaction.
15386
* @property _headers
15391
'X-Requested-With' : 'XMLHttpRequest'
15395
* @description Object that stores timeout values for any transaction with
15396
* a defined "timeout" configuration property.
15398
* @property _timeout
15404
//--------------------------------------
15406
//--------------------------------------
15408
_init: function(c) {
15413
Y.augment(io, Y.EventTarget);
15414
for (i = 0; i < 5; i++) {
15415
// Publish IO global events with configurations, if any.
15416
// IO global events are set to broadcast by default.
15417
// These events use the "io:" namespace.
15418
io.publish('io:' + E[i], Y.merge({ broadcast: 1 }, c));
15419
// Publish IO transaction events with configurations, if
15420
// any. These events use the "io-trn:" namespace.
15421
io.publish('io-trn:' + E[i], c);
15426
* @description Method that creates a unique transaction object for each
15431
* @param {number} c - configuration object subset to determine if
15432
* the transaction is an XDR or file upload,
15433
* requiring an alternate transport.
15434
* @param {number} i - transaction id
15437
_create: function(c, i) {
15439
o = { id: L.isNumber(i) ? i : io._id++, uid: io._uid },
15441
u = x ? x.use : c.form && c.form.upload ? 'iframe' : 'xhr',
15442
ie = (x && x.use === 'native' && xdr),
15448
o.c = ie ? new xdr() : xhr ? new xhr() : new ActiveXObject('Microsoft.XMLHTTP');
15449
o.t = ie ? true : false;
15452
o.c = t ? t[u] : {};
15459
_destroy: function(o) {
15461
if (xhr && o.t === true) {
15462
o.c.onreadystatechange = null;
15464
else if (Y.UA.ie) {
15465
// IE, when using XMLHttpRequest as an ActiveX Object, will throw
15466
// a "Type Mismatch" error if the event handler is set to "null".
15476
* @description Method for creating and firing events.
15480
* @param {string} e - event to be published.
15481
* @param {object} o - transaction object.
15482
* @param {object} c - configuration data subset for event subscription.
15486
_evt: function(e, o, c) {
15488
a = c['arguments'],
15489
eF = io.cfg.emitFacade,
15490
// Use old-style parameters or use an Event Facade
15491
p = eF ? [{ id: o.id, data: o.c, cfg: c, arguments: a }] : [o.id],
15492
// IO Global events namespace.
15494
// IO Transaction events namespace.
15495
tE = "io-trn:" + e;
15498
if (e === E[0] || e === E[2]) {
15504
a ? p.push(o.c, a) : p.push(o.c);
15509
io.fire.apply(io, p);
15512
io.once(tE, c.on[e], c.context || Y);
15513
io.fire.apply(io, p);
15518
* @description Fires event "io:start" and creates, fires a
15519
* transaction-specific start event, if config.on.start is
15524
* @param {object} o - transaction object.
15525
* @param {object} c - configuration object for the transaction.
15529
start: function(o, c) {
15530
this._evt(E[0], o, c);
15534
* @description Fires event "io:complete" and creates, fires a
15535
* transaction-specific "complete" event, if config.on.complete is
15540
* @param {object} o - transaction object.
15541
* @param {object} c - configuration object for the transaction.
15545
complete: function(o, c) {
15546
this._evt(E[1], o, c);
15550
* @description Fires event "io:end" and creates, fires a
15551
* transaction-specific "end" event, if config.on.end is
15556
* @param {object} o - transaction object.
15557
* @param {object} c - configuration object for the transaction.
15561
end: function(o, c) {
15562
this._evt(E[2], o, c);
15567
* @description Fires event "io:success" and creates, fires a
15568
* transaction-specific "success" event, if config.on.success is
15573
* @param {object} o - transaction object.
15574
* @param {object} c - configuration object for the transaction.
15578
success: function(o, c) {
15579
this._evt(E[3], o, c);
15584
* @description Fires event "io:failure" and creates, fires a
15585
* transaction-specific "failure" event, if config.on.failure is
15590
* @param {object} o - transaction object.
15591
* @param {object} c - configuration object for the transaction.
15595
failure: function(o, c) {
15596
this._evt(E[4], o, c);
15601
* @description Retry an XDR transaction, using the Flash tranport,
15602
* if the native transport fails.
15607
* @param {object} o - Transaction object generated by _create().
15608
* @param {string} uri - qualified path to transaction resource.
15609
* @param {object} c - configuration object for the transaction.
15613
_retry: function(o, uri, c) {
15615
c.xdr.use = 'flash';
15616
return this.send(uri, c, o.id);
15620
* @description Method that concatenates string data for HTTP GET transactions.
15624
* @param {string} s - URI or root data.
15625
* @param {string} d - data to be concatenated onto URI.
15628
_concat: function(s, d) {
15629
s += (s.indexOf('?') === -1 ? '?' : '&') + d;
15634
* @description Method that stores default client headers for all transactions.
15635
* If a label is passed with no value argument, the header will be deleted.
15637
* @method _setHeader
15639
* @param {string} l - HTTP header
15640
* @param {string} v - HTTP header value
15643
setHeader: function(l, v) {
15645
this._headers[l] = v;
15648
delete this._headers[l];
15653
* @description Method that sets all HTTP headers to be sent in a transaction.
15655
* @method _setHeaders
15657
* @param {object} o - XHR instance for the specific transaction.
15658
* @param {object} h - HTTP headers for the specific transaction, as defined
15659
* in the configuration object passed to YUI.io().
15662
_setHeaders: function(o, h) {
15663
h = Y.merge(this._headers, h);
15664
Y.Object.each(h, function(v, p) {
15665
if (v !== 'disable') {
15666
o.setRequestHeader(p, h[p]);
15672
* @description Starts timeout count if the configuration object
15673
* has a defined timeout property.
15675
* @method _startTimeout
15677
* @param {object} o - Transaction object generated by _create().
15678
* @param {object} t - Timeout in milliseconds.
15681
_startTimeout: function(o, t) {
15683
io._timeout[o.id] = w.setTimeout(function() { io._abort(o, 'timeout'); }, t);
15687
* @description Clears the timeout interval started by _startTimeout().
15689
* @method _clearTimeout
15691
* @param {number} id - Transaction id.
15694
_clearTimeout: function(id) {
15695
w.clearTimeout(this._timeout[id]);
15696
delete this._timeout[id];
15700
* @description Method that determines if a transaction response qualifies
15701
* as success or failure, based on the response HTTP status code, and
15702
* fires the appropriate success or failure events.
15707
* @param {object} o - Transaction object generated by _create().
15708
* @param {object} c - Configuration object passed to io().
15711
_result: function(o, c) {
15712
var s = o.c.status;
15714
// IE reports HTTP 204 as HTTP 1223.
15715
if (s >= 200 && s < 300 || s === 1223) {
15716
this.success(o, c);
15719
this.failure(o, c);
15724
* @description Event handler bound to onreadystatechange.
15728
* @param {object} o - Transaction object generated by _create().
15729
* @param {object} c - Configuration object passed to YUI.io().
15732
_rS: function(o, c) {
15735
if (o.c.readyState === 4) {
15737
io._clearTimeout(o.id);
15740
// Yield in the event of request timeout or abort.
15741
w.setTimeout(function() { io.complete(o, c); io._result(o, c); }, 0);
15746
* @description Terminates a transaction due to an explicit abort or
15751
* @param {object} o - Transaction object generated by _create().
15752
* @param {string} s - Identifies timed out or aborted transaction.
15756
_abort: function(o, s) {
15764
* @description Method for requesting a transaction. send() is implemented as
15765
* yui.io(). Each transaction may include a configuration object. Its
15768
* method: HTTP method verb (e.g., GET or POST). If this property is not
15769
* not defined, the default value will be GET.
15771
* data: This is the name-value string that will be sent as the transaction
15772
* data. If the request is HTTP GET, the data become part of
15773
* querystring. If HTTP POST, the data are sent in the message body.
15775
* xdr: Defines the transport to be used for cross-domain requests. By
15776
* setting this property, the transaction will use the specified
15777
* transport instead of XMLHttpRequest.
15778
* The properties are:
15780
* use: Specify the transport to be used: 'flash' and 'native'
15781
* dataType: Set the value to 'XML' if that is the expected
15782
* response content type.
15786
* form: This is a defined object used to process HTML form as data. The
15789
* id: Node object or id of HTML form.
15790
* useDisabled: Boolean value to allow disabled HTML form field
15791
* values to be sent as part of the data.
15794
* on: This is a defined object used to create and handle specific
15795
* events during a transaction lifecycle. These events will fire in
15796
* addition to the global io events. The events are:
15797
* start - This event is fired when a request is sent to a resource.
15798
* complete - This event fires when the transaction is complete.
15799
* success - This event fires when the response status resolves to
15801
* failure - This event fires when the response status resolves to
15802
* HTTP 4xx, 5xx; and, for all transaction exceptions,
15803
* including aborted transactions and transaction timeouts.
15804
* end - This even is fired at the conclusion of the transaction
15805
* lifecycle, after a success or failure resolution.
15807
* The properties are:
15809
* start: function(id, arguments){},
15810
* complete: function(id, responseobject, arguments){},
15811
* success: function(id, responseobject, arguments){},
15812
* failure: function(id, responseobject, arguments){},
15813
* end: function(id, arguments){}
15815
* Each property can reference a function or be written as an
15818
* sync: To enable synchronous transactions, set the configuration property
15819
* "sync" to true. Synchronous requests are limited to same-domain
15822
* context: Object reference for all defined transaction event handlers
15823
* when it is implemented as a method of a base object. Defining
15824
* "context" will set the reference of "this," used in the
15825
* event handlers, to the context value. In the case where
15826
* different event handlers all have different contexts,
15827
* use Y.bind() to set the execution context, instead.
15829
* headers: This is a defined object of client headers, as many as
15830
* desired for this specific transaction. The object pattern is:
15831
* { 'header': 'value' }.
15833
* timeout: This value, defined as milliseconds, is a time threshold for the
15834
* transaction. When this threshold is reached, and the transaction's
15835
* Complete event has not yet fired, the transaction will be aborted.
15837
* arguments: User-defined data passed to all registered event handlers.
15838
* This value is available as the second argument in the "start"
15839
* and "end" event handlers. It is the third argument in the
15840
* "complete", "success", and "failure" event handlers.
15845
* @param {string} uri - qualified path to transaction resource.
15846
* @param {object} c - configuration object for the transaction.
15847
* @param {number} i - transaction id, if already set.
15850
send: function(uri, c, i) {
15851
var o, m, r, s, d, io = this,
15853
c = c ? Y.Object(c) : {};
15854
o = io._create(c, i);
15855
m = c.method ? c.method.toUpperCase() : 'GET';
15859
// Serialize an object into a key-value string using
15860
// querystring-stringify-simple.
15861
if (L.isObject(d)) {
15862
d = Y.QueryString.stringify(d);
15866
if (c.form.upload) {
15867
// This is a file upload transaction, calling
15868
// upload() in io-upload-iframe.
15869
return io.upload(o, uri, c);
15872
// Serialize HTML form data into a key-value string.
15873
d = io._serialize(c.form, d);
15882
u = io._concat(u, d);
15884
Y.log('HTTP' + m + ' with data. The querystring is: ' + u, 'info', 'io');
15888
// If Content-Type is defined in the configuration object, or
15889
// or as a default header, it will be used instead of
15890
// 'application/x-www-form-urlencoded; charset=UTF-8'
15891
c.headers = Y.merge({ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, c.headers);
15897
// Cross-domain request or custom transport configured.
15898
return io.xdr(u, o, c);
15902
o.c.onreadystatechange = function() { io._rS(o, c); };
15906
// Determine if request is to be set as
15907
// synchronous or asynchronous.
15908
o.c.open(m, u, s ? false : true, c.username || null, c.password || null);
15909
io._setHeaders(o.c, c.headers || {});
15912
// Will work only in browsers that implement the
15913
// Cross-Origin Resource Sharing draft.
15914
if (c.xdr && c.xdr.credentials) {
15916
o.c.withCredentials = true;
15920
// Using "null" with HTTP POST will result in a request
15921
// with no Content-Length header defined.
15925
// Create a response object for synchronous transactions,
15926
// mixing id and arguments properties with the xhr
15927
// properties whitelist.
15928
r = Y.mix({ id: o.id, 'arguments': c['arguments'] }, o.c, false, P);
15929
r[aH] = function() { return o.c[aH](); };
15930
r[oH] = function(h) { return o.c[oH](h); };
15939
// This exception is usually thrown by browsers
15940
// that do not support XMLHttpRequest Level 2.
15941
// Retry the request with the XDR transport set
15942
// to 'flash'. If the Flash transport is not
15943
// initialized or available, the transaction
15944
// will resolve to a transport error.
15945
return io._retry(o, uri, c);
15953
// If config.timeout is defined, and the request is standard XHR,
15954
// initialize timeout polling.
15956
io._startTimeout(o, c.timeout);
15957
Y.log('Configuration timeout set to: ' + c.timeout, 'info', 'io');
15962
abort: function() {
15963
return o.c ? io._abort(o, 'abort') : false;
15965
isInProgress: function() {
15966
return o.c ? o.c.readyState !== 4 && o.c.readyState !== 0 : false;
15974
* @description Method for requesting a transaction.
15979
* @param {string} u - qualified path to transaction resource.
15980
* @param {object} c - configuration object for the transaction.
15983
Y.io = function(u, c) {
15984
// Calling IO through the static interface will use and reuse
15985
// an instance of IO.
15986
var o = Y.io._map['io:0'] || new IO();
15987
return o.send.apply(o, [u, c]);
15991
// Map of all IO instances created.
15996
}, '3.4.1' ,{requires:['event-custom-base', 'querystring-stringify-simple']});
15997
YUI.add('json-parse', function(Y) {
16000
* <p>The JSON module adds support for serializing JavaScript objects into
16001
* JSON strings and parsing JavaScript objects from strings in JSON format.</p>
16003
* <p>The JSON namespace is added to your YUI instance including static methods
16004
* Y.JSON.parse(..) and Y.JSON.stringify(..).</p>
16006
* <p>The functionality and method signatures follow the ECMAScript 5
16007
* specification. In browsers with native JSON support, the native
16008
* implementation is used.</p>
16010
* <p>The <code>json</code> module is a rollup of <code>json-parse</code> and
16011
* <code>json-stringify</code>.</p>
16013
* <p>As their names suggest, <code>json-parse</code> adds support for parsing
16014
* JSON data (Y.JSON.parse) and <code>json-stringify</code> for serializing
16015
* JavaScript data into JSON strings (Y.JSON.stringify). You may choose to
16016
* include either of the submodules individually if you don't need the
16017
* complementary functionality, or include the rollup for both.</p>
16025
* Provides Y.JSON.parse method to accept JSON strings and return native
16026
* JavaScript objects.
16029
* @submodule json-parse
16035
// All internals kept private for security reasons
16036
function fromGlobal(ref) {
16037
return (Y.config.win || this || {})[ref];
16042
* Alias to native browser implementation of the JSON object if available.
16048
var _JSON = fromGlobal('JSON'),
16050
Native = (Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON),
16051
useNative = !!Native,
16054
* Replace certain Unicode characters that JavaScript may handle incorrectly
16055
* during eval--either by deleting them or treating them as line
16056
* endings--with escape sequences.
16057
* IMPORTANT NOTE: This regex will be used to modify the input if a match is
16060
* @property _UNICODE_EXCEPTIONS
16064
_UNICODE_EXCEPTIONS = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
16068
* First step in the safety evaluation. Regex used to replace all escape
16069
* sequences (i.e. "\\", etc) with '@' characters (a non-JSON character).
16071
* @property _ESCAPES
16075
_ESCAPES = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
16078
* Second step in the safety evaluation. Regex used to replace all simple
16079
* values with ']' characters.
16081
* @property _VALUES
16085
_VALUES = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
16088
* Third step in the safety evaluation. Regex used to remove all open
16089
* square brackets following a colon, comma, or at the beginning of the
16092
* @property _BRACKETS
16096
_BRACKETS = /(?:^|:|,)(?:\s*\[)+/g,
16099
* Final step in the safety evaluation. Regex used to test the string left
16100
* after all previous replacements for invalid characters.
16102
* @property _UNSAFE
16106
_UNSAFE = /[^\],:{}\s]/,
16109
* Replaces specific unicode characters with their appropriate \unnnn
16110
* format. Some browsers ignore certain characters during eval.
16112
* @method escapeException
16113
* @param c {String} Unicode character
16114
* @return {String} the \unnnn escapement of the character
16117
_escapeException = function (c) {
16118
return '\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4);
16122
* Traverses nested objects, applying a reviver function to each (key,value)
16123
* from the scope if the key:value's containing object. The value returned
16124
* from the function will replace the original value in the key:value pair.
16125
* If the value returned is undefined, the key will be omitted from the
16129
* @param data {MIXED} Any JavaScript data
16130
* @param reviver {Function} filter or mutation function
16131
* @return {MIXED} The results of the filtered data
16134
_revive = function (data, reviver) {
16135
var walk = function (o,key) {
16136
var k,v,value = o[key];
16137
if (value && typeof value === 'object') {
16139
if (value.hasOwnProperty(k)) {
16140
v = walk(value, k);
16141
if (v === undefined) {
16149
return reviver.call(o,key,value);
16152
return typeof reviver === 'function' ? walk({'':data},'') : data;
16156
* Parse a JSON string, returning the native JavaScript representation.
16158
* @param s {string} JSON string data
16159
* @param reviver {function} (optional) function(k,v) passed each key value
16160
* pair of object literals, allowing pruning or altering values
16161
* @return {MIXED} the native JavaScript representation of the JSON string
16162
* @throws SyntaxError
16166
// JavaScript implementation in lieu of native browser support. Based on
16167
// the json2.js library from http://json.org
16168
_parse = function (s,reviver) {
16169
// Replace certain Unicode characters that are otherwise handled
16170
// incorrectly by some browser implementations.
16171
// NOTE: This modifies the input if such characters are found!
16172
s = s.replace(_UNICODE_EXCEPTIONS, _escapeException);
16174
// Test for any remaining invalid characters
16175
if (!_UNSAFE.test(s.replace(_ESCAPES,'@').
16176
replace(_VALUES,']').
16177
replace(_BRACKETS,''))) {
16179
// Eval the text into a JavaScript data structure, apply any
16180
// reviver function, and return
16181
return _revive( eval('(' + s + ')'), reviver );
16184
throw new SyntaxError('JSON.parse');
16187
Y.namespace('JSON').parse = function (s,reviver) {
16188
if (typeof s !== 'string') {
16192
return Native && Y.JSON.useNativeParse ?
16193
Native.parse(s,reviver) : _parse(s,reviver);
16196
function workingNative( k, v ) {
16197
return k === "ok" ? true : v;
16200
// Double check basic functionality. This is mainly to catch early broken
16201
// implementations of the JSON API in Firefox 3.1 beta1 and beta2
16204
useNative = ( Native.parse( '{"ok":false}', workingNative ) ).ok;
16212
* Leverage native JSON parse if the browser has a native implementation.
16213
* In general, this is a good idea. See the Known Issues section in the
16214
* JSON user guide for caveats. The default value is true for browsers with
16215
* native JSON support.
16217
* @property useNativeParse
16222
Y.JSON.useNativeParse = useNative;
16226
YUI.add('transition', function(Y) {
16229
* Provides the transition method for Node.
16230
* Transition has no API of its own, but adds the transition method to Node.
16232
* @module transition
16233
* @requires node-style
16236
var CAMEL_VENDOR_PREFIX = '',
16237
VENDOR_PREFIX = '',
16238
DOCUMENT = Y.config.doc,
16239
DOCUMENT_ELEMENT = 'documentElement',
16240
TRANSITION = 'transition',
16241
TRANSITION_CAMEL = 'Transition',
16242
TRANSITION_PROPERTY_CAMEL,
16243
TRANSITION_PROPERTY,
16244
TRANSITION_DURATION,
16245
TRANSITION_TIMING_FUNCTION,
16258
VENDOR_TRANSITION_END = {
16259
Webkit: 'webkitTransitionEnd'
16263
* A class for constructing transition instances.
16264
* Adds the "transition" method to Node.
16265
* @class Transition
16269
Transition = function() {
16270
this.init.apply(this, arguments);
16273
Transition._toCamel = function(property) {
16274
property = property.replace(/-([a-z])/gi, function(m0, m1) {
16275
return m1.toUpperCase();
16281
Transition._toHyphen = function(property) {
16282
property = property.replace(/([A-Z]?)([a-z]+)([A-Z]?)/g, function(m0, m1, m2, m3) {
16283
var str = ((m1) ? '-' + m1.toLowerCase() : '') + m2;
16286
str += '-' + m3.toLowerCase();
16295
Transition.SHOW_TRANSITION = 'fadeIn';
16296
Transition.HIDE_TRANSITION = 'fadeOut';
16298
Transition.useNative = false;
16300
Y.Array.each(VENDORS, function(val) { // then vendor specific
16301
var property = val + TRANSITION_CAMEL;
16302
if (property in DOCUMENT[DOCUMENT_ELEMENT].style) {
16303
CAMEL_VENDOR_PREFIX = val;
16304
VENDOR_PREFIX = Transition._toHyphen(val) + '-';
16306
Transition.useNative = true;
16307
Transition.supported = true; // TODO: remove
16308
Transition._VENDOR_PREFIX = val;
16312
TRANSITION_CAMEL = CAMEL_VENDOR_PREFIX + TRANSITION_CAMEL;
16313
TRANSITION_PROPERTY_CAMEL = CAMEL_VENDOR_PREFIX + 'TransitionProperty';
16314
TRANSITION_PROPERTY = VENDOR_PREFIX + 'transition-property';
16315
TRANSITION_DURATION = VENDOR_PREFIX + 'transition-duration';
16316
TRANSITION_TIMING_FUNCTION = VENDOR_PREFIX + 'transition-timing-function';
16317
TRANSITION_DELAY = VENDOR_PREFIX + 'transition-delay';
16318
TRANSITION_END = 'transitionend';
16319
ON_TRANSITION_END = 'on' + CAMEL_VENDOR_PREFIX.toLowerCase() + 'transitionend';
16321
TRANSITION_END = VENDOR_TRANSITION_END[CAMEL_VENDOR_PREFIX] || TRANSITION_END;
16323
TRANSFORM_CAMEL = CAMEL_VENDOR_PREFIX + 'Transform';
16325
Transition.fx = {};
16326
Transition.toggles = {};
16328
Transition._hasEnd = {};
16330
Transition._reKeywords = /^(?:node|duration|iterations|easing|delay|on|onstart|onend)$/i;
16332
Y.Node.DOM_EVENTS[TRANSITION_END] = 1;
16334
Transition.NAME = 'transition';
16336
Transition.DEFAULT_EASING = 'ease';
16337
Transition.DEFAULT_DURATION = 0.5;
16338
Transition.DEFAULT_DELAY = 0;
16340
Transition._nodeAttrs = {};
16342
Transition.prototype = {
16343
constructor: Transition,
16344
init: function(node, config) {
16347
if (!anim._running && config) {
16348
anim._config = config;
16349
node._transition = anim; // cache for reuse
16351
anim._duration = ('duration' in config) ?
16352
config.duration: anim.constructor.DEFAULT_DURATION;
16354
anim._delay = ('delay' in config) ?
16355
config.delay: anim.constructor.DEFAULT_DELAY;
16357
anim._easing = config.easing || anim.constructor.DEFAULT_EASING;
16358
anim._count = 0; // track number of animated properties
16359
anim._running = false;
16366
addProperty: function(prop, config) {
16369
uid = Y.stamp(node),
16370
nodeInstance = Y.one(node),
16371
attrs = Transition._nodeAttrs[uid],
16379
attrs = Transition._nodeAttrs[uid] = {};
16382
attr = attrs[prop];
16384
// might just be a value
16385
if (config && config.value !== undefined) {
16386
val = config.value;
16387
} else if (config !== undefined) {
16389
config = EMPTY_OBJ;
16392
if (typeof val === 'function') {
16393
val = val.call(nodeInstance, nodeInstance);
16396
if (attr && attr.transition) {
16397
// take control if another transition owns this property
16398
if (attr.transition !== anim) {
16399
attr.transition._count--; // remapping attr to this transition
16403
anim._count++; // properties per transition
16405
// make 0 async and fire events
16406
dur = ((typeof config.duration != 'undefined') ? config.duration :
16407
anim._duration) || 0.0001;
16412
delay: (typeof config.delay != 'undefined') ? config.delay :
16415
easing: config.easing || anim._easing,
16420
// native end event doesnt fire when setting to same value
16421
// supplementing with timer
16422
// val may be a string or number (height: 0, etc), but computedStyle is always string
16423
computed = Y.DOM.getComputedStyle(node, prop);
16424
compareVal = (typeof val === 'string') ? computed : parseFloat(computed);
16426
if (Transition.useNative && compareVal === val) {
16427
setTimeout(function() {
16428
anim._onNativeEnd.call(node, {
16429
propertyName: prop,
16436
removeProperty: function(prop) {
16438
attrs = Transition._nodeAttrs[Y.stamp(anim._node)];
16440
if (attrs && attrs[prop]) {
16441
delete attrs[prop];
16447
initAttrs: function(config) {
16451
if (config.transform && !config[TRANSFORM_CAMEL]) {
16452
config[TRANSFORM_CAMEL] = config.transform;
16453
delete config.transform; // TODO: copy
16456
for (attr in config) {
16457
if (config.hasOwnProperty(attr) && !Transition._reKeywords.test(attr)) {
16458
this.addProperty(attr, config[attr]);
16460
// when size is auto or % webkit starts from zero instead of computed
16461
// (https://bugs.webkit.org/show_bug.cgi?id=16020)
16462
// TODO: selective set
16463
if (node.style[attr] === '') {
16464
Y.DOM.setStyle(node, attr, Y.DOM.getComputedStyle(node, attr));
16471
* Starts or an animation.
16476
run: function(callback) {
16479
config = anim._config,
16481
type: 'transition:start',
16486
if (!anim._running) {
16487
anim._running = true;
16489
//anim._node.fire('transition:start', data);
16491
if (config.on && config.on.start) {
16492
config.on.start.call(Y.one(node), data);
16495
anim.initAttrs(anim._config);
16497
anim._callback = callback;
16505
_start: function() {
16509
_prepDur: function(dur) {
16510
dur = parseFloat(dur);
16515
_runNative: function(time) {
16518
uid = Y.stamp(node),
16519
style = node.style,
16520
computed = getComputedStyle(node),
16521
attrs = Transition._nodeAttrs[uid],
16523
cssTransition = computed[Transition._toCamel(TRANSITION_PROPERTY)],
16525
transitionText = TRANSITION_PROPERTY + ': ',
16526
duration = TRANSITION_DURATION + ': ',
16527
easing = TRANSITION_TIMING_FUNCTION + ': ',
16528
delay = TRANSITION_DELAY + ': ',
16533
// preserve existing transitions
16534
if (cssTransition !== 'all') {
16535
transitionText += cssTransition + ',';
16536
duration += computed[Transition._toCamel(TRANSITION_DURATION)] + ',';
16537
easing += computed[Transition._toCamel(TRANSITION_TIMING_FUNCTION)] + ',';
16538
delay += computed[Transition._toCamel(TRANSITION_DELAY)] + ',';
16542
// run transitions mapped to this instance
16543
for (name in attrs) {
16544
hyphy = Transition._toHyphen(name);
16545
attr = attrs[name];
16546
if ((attr = attrs[name]) && attr.transition === anim) {
16547
if (name in node.style) { // only native styles allowed
16548
duration += anim._prepDur(attr.duration) + ',';
16549
delay += anim._prepDur(attr.delay) + ',';
16550
easing += (attr.easing) + ',';
16552
transitionText += hyphy + ',';
16553
cssText += hyphy + ': ' + attr.value + '; ';
16555
this.removeProperty(name);
16560
transitionText = transitionText.replace(/,$/, ';');
16561
duration = duration.replace(/,$/, ';');
16562
easing = easing.replace(/,$/, ';');
16563
delay = delay.replace(/,$/, ';');
16565
// only one native end event per node
16566
if (!Transition._hasEnd[uid]) {
16567
//anim._detach = Y.on(TRANSITION_END, anim._onNativeEnd, node);
16568
//node[ON_TRANSITION_END] = anim._onNativeEnd;
16569
node.addEventListener(TRANSITION_END, anim._onNativeEnd, '');
16570
Transition._hasEnd[uid] = true;
16574
//setTimeout(function() { // allow updates to apply (size fix, onstart, etc)
16575
style.cssText += transitionText + duration + easing + delay + cssText;
16580
_end: function(elapsed) {
16583
callback = anim._callback,
16584
config = anim._config,
16586
type: 'transition:end',
16588
elapsedTime: elapsed
16591
nodeInstance = Y.one(node);
16593
anim._running = false;
16594
anim._callback = null;
16597
if (config.on && config.on.end) {
16598
setTimeout(function() { // IE: allow previous update to finish
16599
config.on.end.call(nodeInstance, data);
16601
// nested to ensure proper fire order
16603
callback.call(nodeInstance, data);
16607
} else if (callback) {
16608
setTimeout(function() { // IE: allow previous update to finish
16609
callback.call(nodeInstance, data);
16612
//node.fire('transition:end', data);
16617
_endNative: function(name) {
16618
var node = this._node,
16619
value = node.ownerDocument.defaultView.getComputedStyle(node, '')[Transition._toCamel(TRANSITION_PROPERTY)];
16621
if (typeof value === 'string') {
16622
value = value.replace(new RegExp('(?:^|,\\s)' + name + ',?'), ',');
16623
value = value.replace(/^,|,$/, '');
16624
node.style[TRANSITION_CAMEL] = value;
16628
_onNativeEnd: function(e) {
16630
uid = Y.stamp(node),
16631
event = e,//e._event,
16632
name = Transition._toCamel(event.propertyName),
16633
elapsed = event.elapsedTime,
16634
attrs = Transition._nodeAttrs[uid],
16635
attr = attrs[name],
16636
anim = (attr) ? attr.transition : null,
16641
anim.removeProperty(name);
16642
anim._endNative(name);
16643
config = anim._config[name];
16646
type: 'propertyEnd',
16647
propertyName: name,
16648
elapsedTime: elapsed,
16652
if (config && config.on && config.on.end) {
16653
config.on.end.call(Y.one(node), data);
16656
//node.fire('transition:propertyEnd', data);
16658
if (anim._count <= 0) { // after propertyEnd fires
16659
anim._end(elapsed);
16664
destroy: function() {
16668
if (anim._detach) {
16669
anim._detach.detach();
16672
//anim._node[ON_TRANSITION_END] = null;
16674
node.removeEventListener(TRANSITION_END, anim._onNativeEnd, false);
16680
Y.Transition = Transition;
16681
Y.TransitionNative = Transition; // TODO: remove
16684
* Animate one or more css properties to a given value. Requires the "transition" module.
16685
* <pre>example usage:
16686
* Y.one('#demo').transition({
16687
* duration: 1, // in seconds, default is 0.5
16688
* easing: 'ease-out', // default is 'ease'
16689
* delay: '1', // delay start for 1 second, default is 0
16694
* opacity: { // per property
16698
* easing: 'ease-in'
16703
* @method transition
16704
* @param {Object} config An object containing one or more style properties, a duration and an easing.
16705
* @param {Function} callback A function to run after the transition has completed.
16708
Y.Node.prototype.transition = function(name, config, callback) {
16710
transitionAttrs = Transition._nodeAttrs[Y.stamp(this._node)],
16711
anim = (transitionAttrs) ? transitionAttrs.transition || null : null,
16715
if (typeof name === 'string') { // named effect, pull config from registry
16716
if (typeof config === 'function') {
16721
fxConfig = Transition.fx[name];
16723
if (config && typeof config !== 'boolean') {
16724
config = Y.clone(config);
16726
for (prop in fxConfig) {
16727
if (fxConfig.hasOwnProperty(prop)) {
16728
if (! (prop in config)) {
16729
config[prop] = fxConfig[prop];
16737
} else { // name is a config, config is a callback or undefined
16742
if (anim && !anim._running) {
16743
anim.init(this, config);
16745
anim = new Transition(this._node, config);
16748
anim.run(callback);
16752
Y.Node.prototype.show = function(name, config, callback) {
16753
this._show(); // show prior to transition
16754
if (name && Y.Transition) {
16755
if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
16756
if (typeof config === 'function') {
16760
name = Transition.SHOW_TRANSITION;
16762
this.transition(name, config, callback);
16764
else if (name && !Y.Transition) { Y.log('unable to transition show; missing transition module', 'warn', 'node'); }
16768
var _wrapCallBack = function(anim, fn, callback) {
16769
return function() {
16774
callback.apply(anim._node, arguments);
16779
Y.Node.prototype.hide = function(name, config, callback) {
16780
if (name && Y.Transition) {
16781
if (typeof config === 'function') {
16786
callback = _wrapCallBack(this, this._hide, callback); // wrap with existing callback
16787
if (typeof name !== 'string' && !name.push) { // named effect or array of effects supercedes default
16788
if (typeof config === 'function') {
16792
name = Transition.HIDE_TRANSITION;
16794
this.transition(name, config, callback);
16795
} else if (name && !Y.Transition) { Y.log('unable to transition hide; missing transition module', 'warn', 'node'); // end if on nex
16803
* Animate one or more css properties to a given value. Requires the "transition" module.
16804
* <pre>example usage:
16805
* Y.all('.demo').transition({
16806
* duration: 1, // in seconds, default is 0.5
16807
* easing: 'ease-out', // default is 'ease'
16808
* delay: '1', // delay start for 1 second, default is 0
16813
* opacity: { // per property
16817
* easing: 'ease-in'
16822
* @method transition
16823
* @param {Object} config An object containing one or more style properties, a duration and an easing.
16824
* @param {Function} callback A function to run after the transition has completed. The callback fires
16825
* once per item in the NodeList.
16828
Y.NodeList.prototype.transition = function(config, callback) {
16829
var nodes = this._nodes,
16833
while ((node = nodes[i++])) {
16834
Y.one(node).transition(config, callback);
16840
Y.Node.prototype.toggleView = function(name, on, callback) {
16841
this._toggles = this._toggles || [];
16842
callback = arguments[arguments.length - 1];
16844
if (typeof name == 'boolean') { // no transition, just toggle
16849
name = name || Y.Transition.DEFAULT_TOGGLE;
16851
if (typeof on == 'undefined' && name in this._toggles) { // reverse current toggle
16852
on = ! this._toggles[name];
16859
callback = _wrapCallBack(this, this._hide, callback);
16862
this._toggles[name] = on;
16863
this.transition(Y.Transition.toggles[name][on], callback);
16868
Y.NodeList.prototype.toggleView = function(name, on, callback) {
16869
var nodes = this._nodes,
16873
while ((node = nodes[i++])) {
16874
Y.one(node).toggleView(name, on, callback);
16880
Y.mix(Transition.fx, {
16901
height: function(node) {
16902
return node.get('scrollHeight') + 'px';
16904
width: function(node) {
16905
return node.get('scrollWidth') + 'px';
16911
start: function() {
16912
var overflow = this.getStyle('overflow');
16913
if (overflow !== 'hidden') { // enable scrollHeight/Width
16914
this.setStyle('overflow', 'hidden');
16915
this._transitionOverflow = overflow;
16920
if (this._transitionOverflow) { // revert overridden value
16921
this.setStyle('overflow', this._transitionOverflow);
16922
delete this._transitionOverflow;
16929
Y.mix(Transition.toggles, {
16930
size: ['sizeOut', 'sizeIn'],
16931
fade: ['fadeOut', 'fadeIn']
16934
Transition.DEFAULT_TOGGLE = 'fade';
16938
}, '3.4.1' ,{requires:['node-style']});
16939
YUI.add('selector-css2', function(Y) {
16942
* The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
16944
* @submodule selector-css2
16949
* Provides helper methods for collecting and filtering DOM elements.
16952
var PARENT_NODE = 'parentNode',
16953
TAG_NAME = 'tagName',
16954
ATTRIBUTES = 'attributes',
16955
COMBINATOR = 'combinator',
16956
PSEUDOS = 'pseudos',
16958
Selector = Y.Selector,
16961
_reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/, // TODO: move?
16962
SORT_RESULTS: true,
16963
_children: function(node, tag) {
16964
var ret = node.children,
16970
if (node.children && tag && node.children.tags) {
16971
children = node.children.tags(tag);
16972
} else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
16973
childNodes = ret || node.childNodes;
16975
for (i = 0; (child = childNodes[i++]);) {
16976
if (child.tagName) {
16977
if (!tag || tag === child.tagName) {
16988
attr: /(\[[^\]]*\])/g,
16989
esc: /\\[:\[\]\(\)#\.\'\>+~"]/gi,
16990
pseudos: /(\([^\)]*\))/g
16994
* Mapping of shorthand tokens to corresponding attribute selector
16995
* @property shorthand
16999
'\\#(-?[_a-z0-9]+[-\\w\\uE000]*)': '[id=$1]',
17000
'\\.(-?[_a-z]+[-\\w\\uE000]*)': '[className~=$1]'
17004
* List of operators and corresponding boolean functions.
17005
* These functions are passed the attribute and the current node's value of the attribute.
17006
* @property operators
17010
'': function(node, attr) { return Y.DOM.getAttribute(node, attr) !== ''; }, // Just test for existence of attribute
17012
//'=': '^{val}$', // equality
17013
'~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
17014
'|=': '^{val}-?' // optional hyphen-delimited
17018
'first-child': function(node) {
17019
return Y.Selector._children(node[PARENT_NODE])[0] === node;
17023
_bruteQuery: function(selector, root, firstOnly) {
17026
tokens = Selector._tokenize(selector),
17027
token = tokens[tokens.length - 1],
17028
rootDoc = Y.DOM._getDoc(root),
17035
// if we have an initial ID, set to root when in document
17037
if (tokens[0] && rootDoc === root &&
17038
(id = tokens[0].id) &&
17039
rootDoc.getElementById(id)) {
17040
root = rootDoc.getElementById(id);
17047
className = token.className;
17048
tagName = token.tagName || '*';
17050
if (root.getElementsByTagName) { // non-IE lacks DOM api on doc frags
17051
// try ID first, unless no root.all && root not in document
17052
// (root.all works off document, but not getElementById)
17053
// TODO: move to allById?
17054
if (id && (root.all || (root.nodeType === 9 || Y.DOM.inDoc(root)))) {
17055
nodes = Y.DOM.allById(id, root);
17057
} else if (className) {
17058
nodes = root.getElementsByClassName(className);
17059
} else { // default to tagName
17060
nodes = root.getElementsByTagName(tagName);
17063
} else { // brute getElementsByTagName('*')
17064
child = root.firstChild;
17066
if (child.tagName) { // only collect HTMLElements
17069
child = child.nextSilbing || child.firstChild;
17072
if (nodes.length) {
17073
ret = Selector._filterNodes(nodes, tokens, firstOnly);
17080
_filterNodes: function(nodes, tokens, firstOnly) {
17083
len = tokens.length,
17088
getters = Y.Selector.getters,
17094
//FUNCTION = 'function',
17100
for (i = 0; (tmpNode = node = nodes[i++]);) {
17105
while (tmpNode && tmpNode.tagName) {
17107
tests = token.tests;
17110
while ((test = tests[--j])) {
17111
operator = test[1];
17112
if (getters[test[0]]) {
17113
value = getters[test[0]](tmpNode, test[0]);
17115
value = tmpNode[test[0]];
17116
// use getAttribute for non-standard attributes
17117
if (value === undefined && tmpNode.getAttribute) {
17118
value = tmpNode.getAttribute(test[0]);
17122
if ((operator === '=' && value !== test[2]) || // fast path for equality
17123
(typeof operator !== 'string' && // protect against String.test monkey-patch (Moo)
17124
operator.test && !operator.test(value)) || // regex test
17125
(!operator.test && // protect against RegExp as function (webkit)
17126
typeof operator === 'function' && !operator(tmpNode, test[0], test[2]))) { // function test
17128
// skip non element nodes or non-matching tags
17129
if ((tmpNode = tmpNode[path])) {
17131
(!tmpNode.tagName ||
17132
(token.tagName && token.tagName !== tmpNode.tagName))
17134
tmpNode = tmpNode[path];
17142
n--; // move to next token
17143
// now that we've passed the test, move up the tree by combinator
17144
if (!pass && (combinator = token.combinator)) {
17145
path = combinator.axis;
17146
tmpNode = tmpNode[path];
17148
// skip non element nodes
17149
while (tmpNode && !tmpNode.tagName) {
17150
tmpNode = tmpNode[path];
17153
if (combinator.direct) { // one pass only
17157
} else { // success if we made it this far
17165
}// while (tmpNode = node = nodes[++i]);
17166
node = tmpNode = null;
17176
axis: 'parentNode',
17182
axis: 'previousSibling',
17190
re: /^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,
17191
fn: function(match, token) {
17192
var operator = match[2] || '',
17193
operators = Selector.operators,
17194
escVal = (match[3]) ? match[3].replace(/\\/g, '') : '',
17197
// add prefiltering for ID and CLASS
17198
if ((match[1] === 'id' && operator === '=') ||
17199
(match[1] === 'className' &&
17200
Y.config.doc.documentElement.getElementsByClassName &&
17201
(operator === '~=' || operator === '='))) {
17202
token.prefilter = match[1];
17207
// escape all but ID for prefilter, which may run through QSA (via Dom.allById)
17208
token[match[1]] = (match[1] === 'id') ? match[3] : escVal;
17213
if (operator in operators) {
17214
test = operators[operator];
17215
if (typeof test === 'string') {
17216
match[3] = escVal.replace(Selector._reRegExpTokens, '\\$1');
17217
test = new RegExp(test.replace('{val}', match[3]));
17221
if (!token.last || token.prefilter !== match[1]) {
17222
return match.slice(1);
17228
re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
17229
fn: function(match, token) {
17230
var tag = match[1].toUpperCase();
17231
token.tagName = tag;
17233
if (tag !== '*' && (!token.last || token.prefilter)) {
17234
return [TAG_NAME, '=', tag];
17236
if (!token.prefilter) {
17237
token.prefilter = 'tagName';
17243
re: /^\s*([>+~]|\s)\s*/,
17244
fn: function(match, token) {
17249
re: /^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,
17250
fn: function(match, token) {
17251
var test = Selector[PSEUDOS][match[1]];
17252
if (test) { // reorder match array and unescape special chars for tests
17254
match[2] = match[2].replace(/\\/g, '');
17256
return [match[2], test];
17257
} else { // selector token not supported (possibly missing CSS3 module)
17264
_getToken: function(token) {
17276
Break selector into token units per simple selector.
17277
Combinator is attached to the previous token.
17279
_tokenize: function(selector) {
17280
selector = selector || '';
17281
selector = Selector._replaceShorthand(Y.Lang.trim(selector));
17282
var token = Selector._getToken(), // one token per simple selector (left selector holds combinator)
17283
query = selector, // original query for debug report
17284
tokens = [], // array of tokens
17285
found = false, // whether or not any matches were found this pass
17286
match, // the regex match
17291
Search for selector patterns, store, and strip them from the selector string
17292
until no patterns match (invalid selector) or we run out of chars.
17294
Multiple attributes and pseudos are allowed, in any order.
17296
'form:first-child[type=button]:not(button)[lang|=en]'
17300
found = false; // reset after full pass
17301
for (i = 0; (parser = Selector._parsers[i++]);) {
17302
if ( (match = parser.re.exec(selector)) ) { // note assignment
17303
if (parser.name !== COMBINATOR ) {
17304
token.selector = selector;
17306
selector = selector.replace(match[0], ''); // strip current match from selector
17307
if (!selector.length) {
17311
if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
17312
match[1] = Selector._attrFilters[match[1]];
17315
test = parser.fn(match, token);
17316
if (test === false) { // selector not supported
17320
token.tests.push(test);
17323
if (!selector.length || parser.name === COMBINATOR) {
17324
tokens.push(token);
17325
token = Selector._getToken(token);
17326
if (parser.name === COMBINATOR) {
17327
token.combinator = Y.Selector.combinators[match[1]];
17333
} while (found && selector.length);
17335
if (!found || selector.length) { // not fully parsed
17336
Y.log('query: ' + query + ' contains unsupported token in: ' + selector, 'warn', 'Selector');
17342
_replaceShorthand: function(selector) {
17343
var shorthand = Selector.shorthand,
17344
esc = selector.match(Selector._re.esc), // pull escaped colon, brackets, etc.
17350
selector = selector.replace(Selector._re.esc, '\uE000');
17353
attrs = selector.match(Selector._re.attr);
17354
pseudos = selector.match(Selector._re.pseudos);
17357
selector = selector.replace(Selector._re.attr, '\uE001');
17361
selector = selector.replace(Selector._re.pseudos, '\uE002');
17365
for (re in shorthand) {
17366
if (shorthand.hasOwnProperty(re)) {
17367
selector = selector.replace(new RegExp(re, 'gi'), shorthand[re]);
17372
for (i = 0, len = attrs.length; i < len; ++i) {
17373
selector = selector.replace(/\uE001/, attrs[i]);
17378
for (i = 0, len = pseudos.length; i < len; ++i) {
17379
selector = selector.replace(/\uE002/, pseudos[i]);
17383
selector = selector.replace(/\[/g, '\uE003');
17384
selector = selector.replace(/\]/g, '\uE004');
17386
selector = selector.replace(/\(/g, '\uE005');
17387
selector = selector.replace(/\)/g, '\uE006');
17390
for (i = 0, len = esc.length; i < len; ++i) {
17391
selector = selector.replace('\uE000', esc[i]);
17399
'class': 'className',
17404
href: function(node, attr) {
17405
return Y.DOM.getAttribute(node, attr);
17410
Y.mix(Y.Selector, SelectorCSS2, true);
17411
Y.Selector.getters.src = Y.Selector.getters.rel = Y.Selector.getters.href;
17413
// IE wants class with native queries
17414
if (Y.Selector.useNative && Y.config.doc.querySelector) {
17415
Y.Selector.shorthand['\\.(-?[_a-z]+[-\\w]*)'] = '[class~=$1]';
17420
}, '3.4.1' ,{requires:['selector-native']});
17421
YUI.add('selector-css3', function(Y) {
17424
* The selector css3 module provides support for css3 selectors.
17426
* @submodule selector-css3
17431
an+b = get every _a_th node starting at the _b_th
17432
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
17433
1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
17434
an+0 = get every _a_th element, "0" may be omitted
17437
Y.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
17439
Y.Selector._getNth = function(node, expr, tag, reverse) {
17440
Y.Selector._reNth.test(expr);
17441
var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
17442
n = RegExp.$2, // "n"
17443
oddeven = RegExp.$3, // "odd" or "even"
17444
b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
17446
siblings = Y.Selector._children(node.parentNode, tag),
17450
a = 2; // always every other
17453
b = (oddeven === 'odd') ? 1 : 0;
17454
} else if ( isNaN(a) ) {
17455
a = (n) ? 1 : 0; // start from the first or no repeat
17458
if (a === 0) { // just the first
17460
b = siblings.length - b + 1;
17463
if (siblings[b - 1] === node) {
17469
} else if (a < 0) {
17470
reverse = !!reverse;
17475
for (var i = b - 1, len = siblings.length; i < len; i += a) {
17476
if ( i >= 0 && siblings[i] === node ) {
17481
for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
17482
if ( i < len && siblings[i] === node ) {
17490
Y.mix(Y.Selector.pseudos, {
17491
'root': function(node) {
17492
return node === node.ownerDocument.documentElement;
17495
'nth-child': function(node, expr) {
17496
return Y.Selector._getNth(node, expr);
17499
'nth-last-child': function(node, expr) {
17500
return Y.Selector._getNth(node, expr, null, true);
17503
'nth-of-type': function(node, expr) {
17504
return Y.Selector._getNth(node, expr, node.tagName);
17507
'nth-last-of-type': function(node, expr) {
17508
return Y.Selector._getNth(node, expr, node.tagName, true);
17511
'last-child': function(node) {
17512
var children = Y.Selector._children(node.parentNode);
17513
return children[children.length - 1] === node;
17516
'first-of-type': function(node) {
17517
return Y.Selector._children(node.parentNode, node.tagName)[0] === node;
17520
'last-of-type': function(node) {
17521
var children = Y.Selector._children(node.parentNode, node.tagName);
17522
return children[children.length - 1] === node;
17525
'only-child': function(node) {
17526
var children = Y.Selector._children(node.parentNode);
17527
return children.length === 1 && children[0] === node;
17530
'only-of-type': function(node) {
17531
var children = Y.Selector._children(node.parentNode, node.tagName);
17532
return children.length === 1 && children[0] === node;
17535
'empty': function(node) {
17536
return node.childNodes.length === 0;
17539
'not': function(node, expr) {
17540
return !Y.Selector.test(node, expr);
17543
'contains': function(node, expr) {
17544
var text = node.innerText || node.textContent || '';
17545
return text.indexOf(expr) > -1;
17548
'checked': function(node) {
17549
return (node.checked === true || node.selected === true);
17552
enabled: function(node) {
17553
return (node.disabled !== undefined && !node.disabled);
17556
disabled: function(node) {
17557
return (node.disabled);
17561
Y.mix(Y.Selector.operators, {
17562
'^=': '^{val}', // Match starts with value
17563
'$=': '{val}$', // Match ends with value
17564
'*=': '{val}' // Match contains value as substring
17567
Y.Selector.combinators['~'] = {
17568
axis: 'previousSibling'
17572
}, '3.4.1' ,{requires:['selector-native', 'selector-css2']});
17573
YUI.add('yui-log', function(Y) {
17576
* Provides console log capability and exposes a custom event for
17577
* console implementations. This module is a `core` YUI module, <a href="../classes/YUI.html#method_log">it's documentation is located under the YUI class</a>.
17580
* @submodule yui-log
17584
LOGEVENT = 'yui:log',
17585
UNDEFINED = 'undefined',
17586
LEVELS = { debug: 1,
17592
* If the 'debug' config is true, a 'yui:log' event will be
17593
* dispatched, which the Console widget and anything else
17594
* can consume. If the 'useBrowserConsole' config is true, it will
17595
* write to the browser console if available. YUI-specific log
17596
* messages will only be present in the -debug versions of the
17597
* JS files. The build system is supposed to remove log statements
17598
* from the raw and minified versions of the files.
17602
* @param {String} msg The message to log.
17603
* @param {String} cat The log category for the message. Default
17604
* categories are "info", "warn", "error", time".
17605
* Custom categories can be used as well. (opt).
17606
* @param {String} src The source of the the message (opt).
17607
* @param {boolean} silent If true, the log event won't fire.
17608
* @return {YUI} YUI instance.
17610
INSTANCE.log = function(msg, cat, src, silent) {
17611
var bail, excl, incl, m, f,
17614
publisher = (Y.fire) ? Y : YUI.Env.globalEvents;
17615
// suppress log message if the config is off or the event stack
17616
// or the event call stack contains a consumer of the yui:log event
17618
// apply source filters
17620
excl = c.logExclude;
17621
incl = c.logInclude;
17622
if (incl && !(src in incl)) {
17624
} else if (incl && (src in incl)) {
17626
} else if (excl && (src in excl)) {
17631
if (c.useBrowserConsole) {
17632
m = (src) ? src + ': ' + msg : msg;
17633
if (Y.Lang.isFunction(c.logFn)) {
17634
c.logFn.call(Y, msg, cat, src);
17635
} else if (typeof console != UNDEFINED && console.log) {
17636
f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log';
17638
} else if (typeof opera != UNDEFINED) {
17639
opera.postError(m);
17643
if (publisher && !silent) {
17645
if (publisher == Y && (!publisher.getEvent(LOGEVENT))) {
17646
publisher.publish(LOGEVENT, {
17651
publisher.fire(LOGEVENT, {
17664
* Write a system message. This message will be preserved in the
17665
* minified and raw versions of the YUI files, unlike log statements.
17668
* @param {String} msg The message to log.
17669
* @param {String} cat The log category for the message. Default
17670
* categories are "info", "warn", "error", time".
17671
* Custom categories can be used as well. (opt).
17672
* @param {String} src The source of the the message (opt).
17673
* @param {boolean} silent If true, the log event won't fire.
17674
* @return {YUI} YUI instance.
17676
INSTANCE.message = function() {
17677
return INSTANCE.log.apply(INSTANCE, arguments);
17681
}, '3.4.1' ,{requires:['yui-base']});
17682
YUI.add('dump', function(Y) {
17685
* Returns a simple string representation of the object or array.
17686
* Other types of objects will be returned unprocessed. Arrays
17687
* are expected to be indexed. Use object notation for
17688
* associative arrays.
17690
* If included, the dump method is added to the YUI instance.
17702
* Returns a simple string representation of the object or array.
17703
* Other types of objects will be returned unprocessed. Arrays
17704
* are expected to be indexed.
17707
* @param {Object} o The object to dump.
17708
* @param {Number} d How deep to recurse child objects, default 3.
17709
* @return {String} the dump result.
17712
dump = function(o, d) {
17713
var i, len, s = [], type = L.type(o);
17715
// Cast non-objects to string
17716
// Skip dates because the std toString is what we want
17717
// Skip HTMLElement-like objects because trying to dump
17718
// an element will cause an unhandled exception in FF 2.x
17719
if (!L.isObject(o)) {
17721
} else if (type == 'date') {
17723
} else if (o.nodeType && o.tagName) {
17724
return o.tagName + '#' + o.id;
17725
} else if (o.document && o.navigator) {
17727
} else if (o.location && o.body) {
17729
} else if (type == 'function') {
17733
// dig into child objects the depth specifed. Default 3
17734
d = (L.isNumber(d)) ? d : 3;
17736
// arrays [1, 2, 3]
17737
if (type == 'array') {
17739
for (i = 0, len = o.length; i < len; i = i + 1) {
17740
if (L.isObject(o[i])) {
17741
s.push((d > 0) ? L.dump(o[i], d - 1) : OBJ);
17747
if (s.length > 1) {
17752
} else if (type == 'regexp') {
17753
s.push(o.toString());
17754
// objects {k1 => v1, k2 => v2}
17758
if (o.hasOwnProperty(i)) {
17761
if (L.isObject(o[i])) {
17762
s.push((d > 0) ? L.dump(o[i], d - 1) : OBJ);
17768
s.push('Error: ' + e.message);
17772
if (s.length > 1) {
17787
YUI.add('transition-timer', function(Y) {
17790
* The Transition Utility provides an API for creating advanced transitions.
17791
* @module transition
17795
* Provides the base Transition class, for animating numeric properties.
17797
* @module transition
17798
* @submodule transition-timer
17802
var Transition = Y.Transition;
17804
Y.mix(Transition.prototype, {
17805
_start: function() {
17806
if (Transition.useNative) {
17813
_runTimer: function() {
17817
Transition._running[Y.stamp(anim)] = anim;
17818
anim._startTime = new Date();
17819
Transition._startTimer();
17822
_endTimer: function() {
17824
delete Transition._running[Y.stamp(anim)];
17825
anim._startTime = null;
17828
_runFrame: function() {
17829
var t = new Date() - this._startTime;
17833
_runAttrs: function(time) {
17836
config = anim._config,
17837
uid = Y.stamp(node),
17838
attrs = Transition._nodeAttrs[uid],
17839
customAttr = Transition.behaviors,
17852
for (name in attrs) {
17853
if ((attribute = attrs[name]) && attribute.transition === anim) {
17854
d = attribute.duration;
17855
delay = attribute.delay;
17856
elapsed = (time - delay) / 1000;
17859
type: 'propertyEnd',
17860
propertyName: name,
17862
elapsedTime: elapsed
17865
setter = (i in customAttr && 'set' in customAttr[i]) ?
17866
customAttr[i].set : Transition.DEFAULT_SETTER;
17874
if (!delay || time >= delay) {
17875
setter(anim, name, attribute.from, attribute.to, t - delay, d - delay,
17876
attribute.easing, attribute.unit);
17879
delete attrs[name];
17882
if (config[name] && config[name].on && config[name].on.end) {
17883
config[name].on.end.call(Y.one(node), data);
17886
//node.fire('transition:propertyEnd', data);
17888
if (!allDone && anim._count <= 0) {
17890
anim._end(elapsed);
17900
_initAttrs: function() {
17902
customAttr = Transition.behaviors,
17903
uid = Y.stamp(anim._node),
17904
attrs = Transition._nodeAttrs[uid],
17915
for (name in attrs) {
17916
if ((attribute = attrs[name]) && attribute.transition === anim) {
17917
duration = attribute.duration * 1000;
17918
delay = attribute.delay * 1000;
17919
easing = attribute.easing;
17920
val = attribute.value;
17922
// only allow supported properties
17923
if (name in anim._node.style || name in Y.DOM.CUSTOM_STYLES) {
17924
begin = (name in customAttr && 'get' in customAttr[name]) ?
17925
customAttr[name].get(anim, name) : Transition.DEFAULT_GETTER(anim, name);
17927
mFrom = Transition.RE_UNITS.exec(begin);
17928
mTo = Transition.RE_UNITS.exec(val);
17930
begin = mFrom ? mFrom[1] : begin;
17931
end = mTo ? mTo[1] : val;
17932
unit = mTo ? mTo[2] : mFrom ? mFrom[2] : ''; // one might be zero TODO: mixed units
17934
if (!unit && Transition.RE_DEFAULT_UNIT.test(name)) {
17935
unit = Transition.DEFAULT_UNIT;
17938
if (typeof easing === 'string') {
17939
if (easing.indexOf('cubic-bezier') > -1) {
17940
easing = easing.substring(13, easing.length - 1).split(',');
17941
} else if (Transition.easings[easing]) {
17942
easing = Transition.easings[easing];
17946
attribute.from = Number(begin);
17947
attribute.to = Number(end);
17948
attribute.unit = unit;
17949
attribute.easing = easing;
17950
attribute.duration = duration + delay;
17951
attribute.delay = delay;
17953
delete attrs[name];
17960
destroy: function() {
17966
Y.mix(Y.Transition, {
17969
* Regex of properties that should use the default unit.
17971
* @property RE_DEFAULT_UNIT
17974
RE_DEFAULT_UNIT: /^width|height|top|right|bottom|left|margin.*|padding.*|border.*$/i,
17977
* The default unit to use with properties that pass the RE_DEFAULT_UNIT test.
17979
* @property DEFAULT_UNIT
17982
DEFAULT_UNIT: 'px',
17985
* Time in milliseconds passed to setInterval for frame processing
17987
* @property intervalTime
17994
* Bucket for custom getters and setters
17996
* @property behaviors
18001
get: function(anim, attr) {
18002
return Y.DOM._getAttrOffset(anim._node, attr);
18008
* The default setter to use when setting object properties.
18010
* @property DEFAULT_SETTER
18013
DEFAULT_SETTER: function(anim, att, from, to, elapsed, duration, fn, unit) {
18014
from = Number(from);
18017
var node = anim._node,
18018
val = Transition.cubicBezier(fn, elapsed / duration);
18020
val = from + val[0] * (to - from);
18023
if (att in node.style || att in Y.DOM.CUSTOM_STYLES) {
18025
Y.DOM.setStyle(node, att, val + unit);
18033
* The default getter to use when getting object properties.
18035
* @property DEFAULT_GETTER
18038
DEFAULT_GETTER: function(anim, att) {
18039
var node = anim._node,
18042
if (att in node.style || att in Y.DOM.CUSTOM_STYLES) {
18043
val = Y.DOM.getComputedStyle(node, att);
18049
_startTimer: function() {
18050
if (!Transition._timer) {
18051
Transition._timer = setInterval(Transition._runFrame, Transition.intervalTime);
18055
_stopTimer: function() {
18056
clearInterval(Transition._timer);
18057
Transition._timer = null;
18061
* Called per Interval to handle each animation frame.
18062
* @method _runFrame
18066
_runFrame: function() {
18069
for (anim in Transition._running) {
18070
if (Transition._running[anim]._runFrame) {
18072
Transition._running[anim]._runFrame();
18077
Transition._stopTimer();
18081
cubicBezier: function(p, t) {
18091
A = x3 - 3 * x2 + 3 * x1 - x0,
18092
B = 3 * x2 - 6 * x1 + 3 * x0,
18093
C = 3 * x1 - 3 * x0,
18095
E = y3 - 3 * y2 + 3 * y1 - y0,
18096
F = 3 * y2 - 6 * y1 + 3 * y0,
18097
G = 3 * y1 - 3 * y0,
18100
x = (((A*t) + B)*t + C)*t + D,
18101
y = (((E*t) + F)*t + G)*t + H;
18107
ease: [0.25, 0, 1, 0.25],
18108
linear: [0, 0, 1, 1],
18109
'ease-in': [0.42, 0, 1, 1],
18110
'ease-out': [0, 0, 0.58, 1],
18111
'ease-in-out': [0.42, 0, 0.58, 1]
18117
RE_UNITS: /^(-?\d*\.?\d*){1}(em|ex|px|in|cm|mm|pt|pc|%)*$/
18120
Transition.behaviors.top = Transition.behaviors.bottom = Transition.behaviors.right = Transition.behaviors.left;
18122
Y.Transition = Transition;
18125
}, '3.4.1' ,{requires:['transition']});
18126
YUI.add('simpleyui', function(Y) {
18132
}, '3.4.1' ,{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']});
18133
var Y = YUI().use('*');